簡單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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM