简单UART的verilog实现

下面摘录我写的简单的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
原文地址:https://www.cnblogs.com/qingkai/p/7729621.html