uart協議--Verilog及仿真


1、協議原理:

UART(universal asynchronous receiver-transmitter)通用異步收發傳輸器。

uart串口通信需要兩根信號線來實現,一根用於串口發送,一根用於串口接收。一開始高電平,然后拉低表示開始位,接着8個數據位,最后拉高表示停止位,並且進入空閑狀態,等待下一次的數據傳輸。

 因為uart通信沒有時鍾,因此只能規定多少時間發送一個二進制位來保證數據收發不會出錯,這就是波特率。這里時鍾頻率50MHz,波特率9600bps,因此發送一個二進制位需要(50_000_000/9600=5208)個時鍾,換言之,計數到5208就發送一位二進制。


2、協議代碼:

代碼由頂層模塊、接收模塊和發送模塊構成。其中仿真的代碼是仿真通過接收模塊接收數據,再發送出來。同樣串口調試助手也是通過接收模塊接收數據,然后再發出來。

頂層模塊:

 1 module uart_top(
 2 input sys_clk,
 3 input sys_rst_n,
 4 input uart_recv,
 5 output uart_send
 6 );
 7     
 8 wire [7:0]data;
 9 wire data_en;
10 
11 uart_recv  
12 #(
13 .BPS_CNT  (52)           //仿真用的,串口調試不用直接刪掉!
14 )
15 u_uart_recv
16 (
17     .sys_clk          (sys_clk),
18     .sys_rst_n        (sys_rst_n),
19     .data_in_recv     (uart_recv),
20     .data_out_recv    (data),
21     .data_en          (data_en)
22 );
23 
24 uart_send 
25 #(
26 .BPS_CNT  (52)          //仿真用的,串口調試不用直接刪掉!
27 )
28 u_uart_send
29 (
30     .sys_clk          (sys_clk),
31     .sys_rst_n        (sys_rst_n),
32     .data_en          (data_en),
33     .data_in_send     (data),
34     .data_out_send    (uart_send)
35 );
36 endmodule 

接收模塊:

  1 module uart_recv
  2 (
  3 input sys_clk,
  4 input sys_rst_n,
  5 input data_in_recv,
  6 output reg[7:0]data_out_recv,
  7 output reg data_en
  8 );
  9 parameter CLK=50_000_000;
 10 parameter UART_BPS=9600;
 11 parameter BPS_CNT=CLK/UART_BPS;
 12 reg data_in_recv_d0;
 13 reg data_in_recv_d1;
 14 reg [15:0]bps_cnt;
 15 reg [3:0]bit_cnt;
 16 reg [7:0]data;
 17 reg flag;
 18 wire start_flag;
 19 
 20 always @(posedge sys_clk or negedge sys_rst_n)begin
 21 if(!sys_rst_n)begin
 22 data_in_recv_d0<=1'b0;
 23 data_in_recv_d1<=1'b0;
 24 end
 25 else begin
 26 data_in_recv_d0<=data_in_recv;
 27 data_in_recv_d1<=data_in_recv_d0;
 28 end
 29 end
 30 assign start_flag=data_in_recv_d1 & (~data_in_recv_d0);
 31 
 32 
 33 always @(posedge sys_clk or negedge sys_rst_n)begin
 34 if(!sys_rst_n)
 35 flag<=1'b0;
 36 else if(start_flag)
 37 flag<=1'b1;
 38 else if((bit_cnt==9)&&(bps_cnt==BPS_CNT/2))
 39 flag<=1'b0;
 40 else
 41 flag<=flag;
 42 end
 43 
 44 always @(posedge sys_clk or negedge sys_rst_n)begin
 45 if(!sys_rst_n)begin
 46 bps_cnt<=16'd0;
 47 bit_cnt<=4'd0;
 48 end
 49 else if(flag)begin
 50 if(bps_cnt<BPS_CNT-1)begin
 51 bps_cnt<=bps_cnt+1'b1;
 52 bit_cnt<=bit_cnt;
 53 end
 54 else begin
 55 bps_cnt<=16'd0;
 56 bit_cnt<=bit_cnt+1;
 57 end
 58 end
 59 else begin
 60 bps_cnt<=16'd0;
 61 bit_cnt<=4'd0;
 62 end
 63 end
 64 
 65 always @(posedge sys_clk or negedge sys_rst_n) begin 
 66     if ( !sys_rst_n)  
 67         data <= 8'd0;                                     
 68     else if(flag)                            
 69         if (bps_cnt == BPS_CNT/2) begin         
 70             case ( bit_cnt )
 71              4'd1 : data[0] <= data_in_recv_d1;   
 72              4'd2 : data[1] <= data_in_recv_d1;
 73              4'd3 : data[2] <= data_in_recv_d1;
 74              4'd4 : data[3] <= data_in_recv_d1;
 75              4'd5 : data[4] <= data_in_recv_d1;
 76              4'd6 : data[5] <= data_in_recv_d1;
 77              4'd7 : data[6] <= data_in_recv_d1;
 78              4'd8 : data[7] <= data_in_recv_d1;   
 79              default:;                                    
 80             endcase
 81         end
 82         else 
 83             data <= data;
 84     else
 85         data <= 8'd0;
 86 end
 87 
 88 always @(posedge sys_clk or negedge sys_rst_n)begin
 89 if(!sys_rst_n)begin
 90 data_out_recv<=8'd0;
 91 data_en<=1'b0;
 92 end
 93 else if(bit_cnt==9)begin
 94 data_out_recv<=data;
 95 data_en<=1'b1;
 96 end
 97 else begin
 98 data_en<=1'b0;
 99 end
100 end
101 endmodule 

發送模塊:

 1 module uart_send
 2 (
 3 input sys_clk,
 4 input sys_rst_n,
 5 input data_en,
 6 input [7:0]data_in_send,
 7 output reg data_out_send
 8 );
 9 parameter CLK=50_000_000;
10 parameter UART_BPS=9600;
11 parameter BPS_CNT=CLK/UART_BPS;
12 reg [7:0]tem_data;
13 reg [15:0]bps_cnt;
14 reg [3:0]bit_cnt;
15 reg send_flag;
16 
17 always @(posedge sys_clk or negedge sys_rst_n)begin
18 if(!sys_rst_n)
19 send_flag<=1'b0;
20 else if(data_en)begin
21 tem_data<=data_in_send;
22 send_flag<=1'b1;
23 end
24 else if((bit_cnt==4'd9)&&(bps_cnt==BPS_CNT/2))begin
25 tem_data<=8'd0;
26 send_flag<=1'b0;
27 end
28 else begin
29 tem_data<=tem_data;
30 send_flag<=send_flag;
31 end
32 end
33 
34 always @(posedge sys_clk or negedge sys_rst_n)begin
35 if(!sys_rst_n)begin
36 bps_cnt<=16'd0;
37 bit_cnt<=4'd0;
38 end
39 else if(send_flag)begin
40 if(bps_cnt<BPS_CNT-1)begin
41 bps_cnt<=bps_cnt+1'b1;
42 bit_cnt<=bit_cnt;
43 end
44 else begin
45 bps_cnt<=16'd0;
46 bit_cnt<=bit_cnt+1'b1;
47 end
48 end
49 else begin
50 bps_cnt<=16'd0;
51 bit_cnt<=4'd0;
52 end
53 end
54 
55 always @(posedge sys_clk or negedge sys_rst_n) begin        
56     if (!sys_rst_n)  
57         data_out_send <= 1'b1;        
58     else if (send_flag)
59         case(bit_cnt)
60             4'd0: data_out_send <= 1'b0;         
61             4'd1: data_out_send <= tem_data[0];  
62             4'd2: data_out_send <= tem_data[1];
63             4'd3: data_out_send <= tem_data[2];
64             4'd4: data_out_send <= tem_data[3];
65             4'd5: data_out_send <= tem_data[4];
66             4'd6: data_out_send <= tem_data[5];
67             4'd7: data_out_send <= tem_data[6];
68             4'd8: data_out_send <= tem_data[7];   
69             4'd9: data_out_send <= 1'b1;       
70             default: ;
71         endcase
72     else 
73         data_out_send <= 1'b1;                  
74 end
75 endmodule 

仿真:

 1 `timescale 1ns/1ns 
 2 module uart_top_tb;
 3 reg                         sys_clk                 ; 
 4 reg                         sys_rst_n              ; 
 5 reg                         uart_recv             ;
 6 wire                        uart_send           ;
 7 
 8 uart_top u_uart_top
 9 (
10     .sys_clk                    (sys_clk                ),
11     .sys_rst_n                  (sys_rst_n              ),
12     .uart_recv                (uart_recv            ),
13     .uart_send                (uart_send            )
14 );
15 
16 initial begin
17     sys_clk = 1;
18 end
19 always #10 sys_clk = ~sys_clk;
20 
21 initial begin
22     sys_rst_n = 0; 
23    #30 sys_rst_n = 1;
24 end
25 
26 reg  [7:0]              mem[15:0]           ; 
27 integer                 i                         ;
28 integer                 j                         ;
29 
30 
31 initial $readmemh("./data.txt",mem);
32 
33 task bit_cnt
34 (
35     input [7:0]         data
36 );
37     begin
38         for(i=0;i<=9;i=i+1) begin   //10?bit?
39             case(i)
40                  0: uart_recv = 1'b0;
41                  1: uart_recv = data[i-1];
42                  2: uart_recv = data[i-1];
43                  3: uart_recv = data[i-1];
44                  4: uart_recv = data[i-1];
45                  5: uart_recv = data[i-1];
46                  6: uart_recv = data[i-1];
47                  7: uart_recv = data[i-1];
48                  8: uart_recv = data[i-1];
49                  9: uart_recv = 1'b1;
50             endcase
51             #1040; 
52         end        
53     end
54 endtask
55 
56 task rx_byte;
57     begin
58         for(j=0;j<=15;j=j+1) 
59             bit_cnt(mem[j]);
60     end
61 endtask
62 
63 initial begin
64     # 401 rx_byte();
65 end
66 
67 initial begin
68     #180000;
69     $stop;
70 end
71 endmodule

 仿真的時候,在sim目錄下建立一個data.txt存放寬度8位,深度16位的文件,然后仿真接收這個文件,然后發出這個文件。

這里的數字是十六進制,比如8'h00  8'h01...

仿真結果以及串口調試結果:

暫時還沒有解惑的地方:

①不明白作者為什么在仿真的時候,頂層模塊這里需要有一個52?

#(
.BPS_CNT (52) //仿真用的,串口調試不用直接刪掉!
)

②根據接收模塊最后的代碼可以知道,當接收成功每一個字(8'h00  8'h01...)的所有二進制位,data_en就會被拉高,前面的8'h00  8'h01...到8'h0e,一直都是接收完之后就拉高data_en,然而為什么到了最后一個字8'h0f就沒有出現了?

參考文章:https://www.cnblogs.com/xianyufpga/p/11086676.html


免責聲明!

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



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