简单UART的verilog实现

10/18 11:52
阅读数 0

下面摘录我写的简单的UART代码,对于灵活性和健壮性做了如下设计:

1、系统时钟及串口波特率以参数形式输入,例化时可以灵活设置

2、接受模块在起始位会检测中点电平是否仍然为低,否则判定为抖动

 

接收机代码

 

 
  1.  
    `timescale 1ns/1ps
  2.  
     
  3.  
    // 系统时钟200MHz,波特率115200
  4.  
    module uart_rx #(
  5.  
    parameter BAUDRATE = 115200,
  6.  
    parameter FREQ = 200_000_000)(
  7.  
    input clk, nrst,
  8.  
    input rx,
  9.  
    output reg [7:0] rdata,
  10.  
    output reg vld
  11.  
    );
  12.  
     
  13.  
    localparam T = FREQ / BAUDRATE;
  14.  
     
  15.  
    // flag接受处理标志位,为1表明当前处于接受状态
  16.  
    reg flag;
  17.  
    always @(posedge clk or negedge nrst) begin
  18.  
    if(nrst == 0)
  19.  
    flag <= 0;
  20.  
    else if(flag == 0 && rx == 0)
  21.  
    flag <= 1;
  22.  
    else if(cnt_bit == 1 - 1 && cnt_clk == T / 2 - 1 && rx == 1)
  23.  
    flag <= 0;
  24.  
    else if(end_cnt_bit)
  25.  
    flag <= 0;
  26.  
    end
  27.  
     
  28.  
    // 两层计数结构,cnt_clk计数每一位所占的时钟数,cnt_bit计数1个开始位,8个数据位,一个停止位,共10位
  29.  
    reg [3:0] cnt_bit;
  30.  
    reg [31:0] cnt_clk;
  31.  
    assign end_cnt_clk = cnt_clk == T - 1;
  32.  
    assign end_cnt_bit = end_cnt_clk && cnt_bit == 10 - 1;
  33.  
     
  34.  
    always @(posedge clk or negedge nrst) begin
  35.  
    if(nrst == 0)
  36.  
    cnt_clk <= 0;
  37.  
    else if(flag) begin
  38.  
    if(end_cnt_clk)
  39.  
    cnt_clk <= 0;
  40.  
    else
  41.  
    cnt_clk <= cnt_clk + 1'b1;
  42.  
    end
  43.  
    else
  44.  
    cnt_clk <= 0;
  45.  
    end
  46.  
     
  47.  
    always @(posedge clk or negedge nrst) begin
  48.  
    if(nrst == 0)
  49.  
    cnt_bit <= 0;
  50.  
    else if(end_cnt_clk) begin
  51.  
    if(end_cnt_bit)
  52.  
    cnt_bit <= 0;
  53.  
    else
  54.  
    cnt_bit <= cnt_bit + 1'b1;
  55.  
    end
  56.  
    end
  57.  
     
  58.  
    // 读数据及数据有效指示信号
  59.  
    always @(posedge clk or negedge nrst) begin
  60.  
    if(nrst == 0)
  61.  
    rdata <= 0;
  62.  
    else if(cnt_clk == T / 2 - 1 && cnt_bit != 1 - 1 && cnt_bit != 10 - 1)
  63.  
    rdata[cnt_bit - 1] <= rx;
  64.  
    end
  65.  
     
  66.  
    always @(posedge clk or negedge nrst) begin
  67.  
    if(nrst == 0)
  68.  
    vld <= 0;
  69.  
    else if(end_cnt_bit)
  70.  
    vld <= 1;
  71.  
    else
  72.  
    vld <= 0;
  73.  
    end
  74.  
     
  75.  
    endmodule

发送机代码

 
  1.  
    `timescale 1ns/1ps
  2.  
     
  3.  
    // 系统时钟200MHz,波特率115200,带忙闲指示信号rdy
  4.  
    module uart_tx #(
  5.  
    parameter BAUDRATE = 115200,
  6.  
    parameter FREQ = 200_000_000)(
  7.  
    input clk, nrst,
  8.  
    input wrreq,
  9.  
    input [7:0] wdata,
  10.  
    output reg tx,
  11.  
    output reg rdy
  12.  
    );
  13.  
     
  14.  
    reg [3:0] cnt_bit;
  15.  
    reg [31:0] cnt_clk;
  16.  
     
  17.  
    localparam T = FREQ / BAUDRATE;
  18.  
     
  19.  
    // 有写请求时将rdy信号拉底,待到数据发送完毕再将信号拉
  20.  
    always @(posedge clk or negedge nrst) begin
  21.  
    if(nrst == 0)
  22.  
    rdy <= 1;
  23.  
    else if(wrreq)
  24.  
    rdy <= 0;
  25.  
    else if(end_cnt_bit)
  26.  
    rdy <= 1;
  27.  
    end
  28.  
     
  29.  
    // 两层计数结构,cnt_clk计数每一位所占的时钟数,cnt_bit计数1个开始位,8个数据位,一个停止位,共10位
  30.  
    wire end_cnt_clk;
  31.  
    wire end_cnt_bit;
  32.  
    assign end_cnt_clk = cnt_clk == T - 1;
  33.  
    assign end_cnt_bit = end_cnt_clk && cnt_bit == 10 - 1;
  34.  
     
  35.  
    always @(posedge clk or negedge nrst) begin
  36.  
    if(nrst == 0)
  37.  
    cnt_clk <= 0;
  38.  
    else if(rdy == 0) begin
  39.  
    if(end_cnt_clk)
  40.  
    cnt_clk <= 0;
  41.  
    else
  42.  
    cnt_clk <= cnt_clk + 1'b1;
  43.  
    end
  44.  
    end
  45.  
     
  46.  
    always @(posedge clk or negedge nrst) begin
  47.  
    if(nrst == 0)
  48.  
    cnt_bit <= 0;
  49.  
    else if(end_cnt_clk) begin
  50.  
    if(end_cnt_bit)
  51.  
    cnt_bit <= 0;
  52.  
    else
  53.  
    cnt_bit <= cnt_bit + 1'b1;
  54.  
    end
  55.  
    end
  56.  
     
  57.  
    // 先发送一个起始位0,然后8位数据位,最后是停止位1
  58.  
    always @(posedge clk or negedge nrst) begin
  59.  
    if(nrst == 0)
  60.  
    tx <= 1;
  61.  
    else if(rdy == 0 && cnt_clk == 0) begin
  62.  
    if(cnt_bit == 1 - 1)
  63.  
    tx <= 0;
  64.  
    else if(cnt_bit == 10 - 1)
  65.  
    tx <= 1;
  66.  
    else
  67.  
    tx <= wdata[cnt_bit - 1];
  68.  
    end
  69.  
    end
  70.  
     
  71.  
    endmodule

在Xilinx Artix-7平台上验证的顶层代码

 
  1.  
    `timescale 1ns / 1ps
  2.  
     
  3.  
    module uart_top(
  4.  
    input clk_p, clk_n, nrst,
  5.  
    input rx,
  6.  
    output tx
  7.  
    );
  8.  
     
  9.  
    localparam BAUDRATE = 115200;
  10.  
    localparam FREQ = 200_000_000;
  11.  
     
  12.  
    // 差分时钟信号转为单端信号
  13.  
    IBUFGDS #(
  14.  
    .DIFF_TERM("FALSE"),
  15.  
    .IBUF_LOW_PWR("TRUE"),
  16.  
    .IOSTANDARD("DEFAULT")
  17.  
    ) IBUFGDS_inst(
  18.  
    .O(clk),
  19.  
    .I(clk_p),
  20.  
    .IB(clk_n)
  21.  
    );
  22.  
     
  23.  
    wire [7:0] data;
  24.  
    wire vld;
  25.  
     
  26.  
    uart_rx #(BAUDRATE, FREQ) uart_rx_u(
  27.  
    .clk (clk ),
  28.  
    .nrst (nrst ),
  29.  
    .rx (rx ),
  30.  
    .rdata (data ),
  31.  
    .vld (vld )
  32.  
    );
  33.  
     
  34.  
    uart_tx #(BAUDRATE, FREQ) uart_tx_u(
  35.  
    .clk (clk ),
  36.  
    .nrst (nrst ),
  37.  
    .wrreq (vld ),
  38.  
    .wdata (data ),
  39.  
    .tx (tx ),
  40.  
    .rdy ( )
  41.  
    );
  42.  
     
  43.  
    ila_0 ila_0_u(
  44.  
    .clk (clk ),
  45.  
    .probe0 (nrst ),
  46.  
    .probe1 ({tx,rx}),
  47.  
    .probe2 (data ),
  48.  
    .probe3 (vld )
  49.  
    );
  50.  
     
  51.  
    endmodule
展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部