基于FPGA的UART实现

    

   通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UATR,是一种异步收发传输器。将数据由串行通信与并行通信间做传输转换,作为并行输入称为串行输出的芯片。UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。

  异步串行通信数据格式  

  UART作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。其中各位的意义如下:

   1、起始位:先发出一个逻辑”0”的信号,表示传输字符的开始。
   2、数据位:起始位之后。资料位的个数可以是4、5、6、7、8等,构成一个字符。通常采用ASCII码。从最低位开始传送,靠时钟定位。
   3、奇偶校验位:资料位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验资料传送的正确性。
   4、停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。 由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
   5、空闲位:处于逻辑“1”状态,表示当前线路上没有数据传输。

 发送一个字节数据的时序图

   波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。典型的波特率有300, 1200, 2400, 9600, 19200, 115200等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。

   假设需要的波特率为9600bps,那么波特率时钟周期约为 104167ns,板载时钟频率为50MHz,周期为20ns,要计数到104167ns,需要5208个板载时钟周期。

发送模块的代码:

 1 module UART_TX(
 2   clk,
 3   rst_n,
 4   
 5   send_en,
 6   tx_done,
 7   
 8   data_in,
 9   
10   uart_tx
11 );
12 
13 input clk;
14 input rst_n;
15 input[7:0] data_in;  // 输入数据
16 input send_en;       // 发送使能
17 
18 output reg tx_done;  // 发送完成标志信号
19 output reg uart_tx;  // 目标信号输出
20 
21 reg[15:0] bps_cnt;   // 波特率计数寄存器
22 reg[3:0] lsm_cnt;    // 序列机计数
23 reg flag;            // 发送标志信号
24 
25 always@(posedge clk or negedge rst_n)  // flag 信号设计
26   if(!rst_n)
27     flag <= 1'b0;
28   else if(send_en)  // 检测到 发送使能信号,则flag信号拉高
29     flag <= 1'b1;
30   else if(lsm_cnt == 10)  // 发送完一个字节后,flag信号拉低
31     flag <= 1'b0;
32      
33 always@(posedge clk or negedge rst_n)  // bps_cnt 信号设计
34   if(!rst_n)
35     bps_cnt <= 16'd0;
36   else if(flag) begin
37     if(bps_cnt == 5207)   //从0开始计数,计数到5207后停止计数,则计数5208次
38        bps_cnt <= 16'd0;
39      else
40        bps_cnt <= bps_cnt + 1'b1;
41   end
42   else
43     bps_cnt <= 16'd0;
44      
45 always@(posedge clk or negedge rst_n)  // lsm_cnt 信号设计
46   if(!rst_n)
47     lsm_cnt <= 4'd0;
48   else if(bps_cnt == 5207)  // 在 bps_cnt == 5207 时,则刚好计数满9600bps的一个周期
49     lsm_cnt <= lsm_cnt + 1'b1;
50   else if(lsm_cnt == 10)
51     lsm_cnt <= 4'd0;
52      
53 always@(posedge clk or negedge rst_n)  // 信号转换
54   if(!rst_n)
55     uart_tx <= 1'b1;
56   else if(flag) begin
57     case(lsm_cnt)
58        0 : uart_tx <= 1'b0;  //起始位
59         1 : uart_tx <= data_in[0];
60         2 : uart_tx <= data_in[1];
61         3 : uart_tx <= data_in[2];
62         4 : uart_tx <= data_in[3];
63         5 : uart_tx <= data_in[4];
64         6 : uart_tx <= data_in[5];
65         7 : uart_tx <= data_in[6];
66         8 : uart_tx <= data_in[7];
67         9 : uart_tx <= 1'b1;  //停止位
68         default: uart_tx <= 1'b1;
69      endcase 
70   end
71   else
72     uart_tx <= 1'b1;
73      
74 always@(posedge clk or negedge rst_n)  // tx_done 信号设计
75   if(!rst_n)
76     tx_done <= 1'b0;
77   else if(flag && lsm_cnt == 10)  // 发送完一个字节数据后拉高tx_done信号
78     tx_done <= 1'b1;
79   else
80     tx_done <= 1'b0;
81      
82 endmodule
View Code

testbench代码:

 1 `timescale 1ns/1ps
 2 module UART_TX_tb;
 3   reg clk;
 4   reg rst_n;
 5   reg send_en;  
 6 
 7   reg[7:0] data_in;
 8   
 9   wire uart_tx;
10   wire tx_done;  
11 
12 UART_TX_TEST u0(
13   .clk(clk),
14   .rst_n(rst_n),
15   .send_en(send_en),
16   .tx_done(tx_done),
17   
18   .data_in(data_in),
19   .uart_tx(uart_tx)
20 );
21 
22 initial
23   clk = 0;
24   always #10 clk = ~clk;
25   
26 initial
27   begin
28     rst_n = 1'b0;
29      data_in = 8'd0;
30      send_en = 1'b0;
31      #21;
32      
33      rst_n = 1'b1;
34      #1000;
35      data_in = 8'haa;
36      send_en = 1'b1;
37      #20;
38      send_en = 1'b0;
39      @(posedge tx_done)
40      
41      #1000000;
42      data_in = 8'h55;
43      send_en = 1'b1;
44      #20;
45      send_en = 1'b0;
46      @(posedge tx_done)
47      
48      #1000000;
49      $stop;
50   end
51 endmodule
View Code

 2020.04.28

修订版代码:

发送模块:uart_tx

 1 // Time : 2020.04.23
 2 // Describe : uart_tx
 3 
 4 module uart_tx(
 5   input          clk,
 6   input          rst_n,
 7   
 8   input          send_en,
 9   input  [7:0]   data_in,
10   
11   output reg     rs232_tx
12 );
13 
14 localparam BAUD_END    = 5207;
15 
16 localparam BAUD_M      = BAUD_END/2 - 1;
17 localparam BIT_END     = 8;
18 
19 reg  [7:0]   data_in_r;
20 reg  [12:0]  baud_cnt;
21 reg          tx_flag;
22 reg          bit_flag;
23 reg  [3:0]   bit_cnt;
24 
25 always@(posedge clk or negedge rst_n) begin
26   if(!rst_n)
27     data_in_r <= 8'd0;
28   else if(send_en == 1'b1 )  // tx_flag == 1'b0  && tx_flag == 1'b1
29     data_in_r <= data_in;
30 end
31 
32 always@(posedge clk or negedge rst_n) begin
33   if(!rst_n)
34     tx_flag <= 1'b0;
35   else if(send_en == 1'b1)
36     tx_flag <= 1'b1;
37   else if(bit_cnt == BIT_END && bit_flag == 1'b1)
38     tx_flag <= 1'b0;
39 end
40 
41 always@(posedge clk or negedge rst_n) begin
42   if(!rst_n)
43     baud_cnt <= 13'd0;
44   else if(baud_cnt == BAUD_END)
45     baud_cnt <= 13'd0;
46   else if(tx_flag == 1'b1)
47     baud_cnt <= baud_cnt + 1'b1;
48   else
49     baud_cnt <= 13'd0;
50 end
51 
52 always@(posedge clk or negedge rst_n) begin
53   if(!rst_n)
54     bit_flag <= 1'b0;
55   else if(baud_cnt == BAUD_END)
56     bit_flag <= 1'b1;
57   else
58     bit_flag <= 1'b0;
59 end
60 
61 always@(posedge clk or negedge rst_n) begin
62   if(!rst_n)
63     bit_cnt <= 4'd0;
64   else if(bit_flag == 1'b1 && bit_cnt == BIT_END)
65     bit_cnt <= 4'd0;
66   else if(bit_flag == 1'b1)
67     bit_cnt <= bit_cnt + 1'b1;
68 end
69 
70 always@(posedge clk or negedge rst_n) begin
71   if(!rst_n)
72     rs232_tx <= 1'b1;
73   else if(tx_flag == 1'b1)
74     case(bit_cnt)
75         0: rs232_tx <= 1'b0;
76         1: rs232_tx <= data_in_r[0];
77         2: rs232_tx <= data_in_r[1];
78         3: rs232_tx <= data_in_r[2];
79         4: rs232_tx <= data_in_r[3];
80         5: rs232_tx <= data_in_r[4];
81         6: rs232_tx <= data_in_r[5];
82         7: rs232_tx <= data_in_r[6];
83         8: rs232_tx <= data_in_r[7];
84       default: rs232_tx <= 1'b1;
85     endcase
86   else
87     rs232_tx <= 1'b1;        
88 end
89 
90 endmodule
View Code

发送模块Modelsim仿真代码:

 1 `timescale 1ns/1ns
 2 module uart_tx_tb;
 3   reg          clk;
 4   reg          rst_n;
 5   
 6   reg          send_en;
 7   reg  [7:0]   data_in;
 8   
 9   wire         rs232_tx;
10   
11 uart_tx u0(
12   .clk(clk),
13   .rst_n(rst_n),
14   
15   .send_en(send_en),
16   .data_in(data_in),
17   
18   .rs232_tx(rs232_tx)
19   
20   );
21   
22 initial
23   clk = 1'b1;
24   always #10 clk = ~clk;
25 
26 initial
27   begin
28     rst_n = 1'b0;
29      data_in = 8'd0;
30      send_en = 1'b0;
31      #100;
32      
33      rst_n = 1'b1;
34      #100;
35      send_en = 1'b1;
36      data_in = 8'h55;
37      #20;
38      send_en = 1'b0;
39      
40      #1000000;
41      $stop;
42   
43   end
44   
45 endmodule
View Code

发送模块仿真截图:

接收模块:uart_rx

 1 // Time : 2020.04.22
 2 // Describe : uart_rx
 3 
 4 module uart_rx(
 5   input           clk,
 6   input           rst_n,
 7          
 8   input           rs232_rx,
 9   
10   output reg      rx_done,
11   output reg[7:0] data_out
12 );
13 
14 localparam BAUD_END    = 5207;
15 localparam BAUD_M      = BAUD_END/2 - 1;
16 localparam BIT_END     = 8;
17 
18 reg           rx_r1,rx_r2,rx_r3;
19 reg           rx_flag;
20           
21 reg           bit_flag;
22 
23 reg    [12:0] baud_cnt;
24 reg    [3:0]  bit_cnt;
25 
26 wire          rx_neg;
27 
28 assign rx_neg = ~rx_r2 & rx_r3;  // 检测rs232_rx的下降沿
29 
30 always@(posedge clk) begin
31   rx_r1 <= rs232_rx;
32   rx_r2 <= rx_r1;
33   rx_r3 <= rx_r2;
34 end
35 
36 always@(posedge clk or negedge rst_n) begin
37   if(!rst_n)
38     rx_flag <= 1'b0;
39   else if(rx_neg == 1'b1)
40     rx_flag <= 1'b1;
41   else if(bit_cnt == 4'd0 && baud_cnt == BAUD_END)
42     rx_flag <= 1'b0;
43 end
44 
45 always@(posedge clk or negedge rst_n) begin
46   if(!rst_n)
47     baud_cnt <= 13'd0;
48   else if(baud_cnt == BAUD_END)
49     baud_cnt <= 13'd0;
50   else if(rx_flag == 1'b1)
51     baud_cnt <= baud_cnt + 1'b1;
52   else
53     baud_cnt <= 13'd0;
54 end
55 
56 always@(posedge clk or negedge rst_n) begin
57   if(!rst_n)
58     bit_flag <= 1'b0;
59   else if(baud_cnt == BAUD_M)
60     bit_flag <= 1'b1;
61   else
62     bit_flag <= 1'b0;
63 end
64 
65 always@(posedge clk or negedge rst_n) begin
66   if(!rst_n)
67     bit_cnt <= 4'd0;
68   else if(bit_flag == 1'b1 && bit_cnt == BIT_END)
69     bit_cnt <= 4'd0;
70   else if(bit_flag == 1'b1)
71     bit_cnt <= bit_cnt + 1'b1;
72 end
73 
74 always@(posedge clk or negedge rst_n) begin
75   if(!rst_n)
76     data_out <= 8'd0;
77   else if(bit_flag == 1'b1 && bit_cnt >= 4'd1)
78     data_out <= {rx_r2,data_out[7:1]};
79 end
80 
81 always@(posedge clk or negedge rst_n) begin
82   if(!rst_n)
83     rx_done <= 1'b0;
84   else if(bit_cnt == BIT_END && bit_flag == 1'b1)
85     rx_done <= 1'b1;
86   else
87     rx_done <= 1'b0;
88 end
89 
90 endmodule
View Code

接收模块Modelsim仿真代码:

 1 `timescale 1ns/1ns
 2 module uart_rx_tb;
 3   reg           clk;
 4   reg           rst_n;
 5          
 6   reg           rs232_rx;
 7   
 8   wire          rx_done;
 9   wire[7:0]     data_out;
10   
11   reg send_en;
12   reg [7:0] data_in;
13   wire rs232_tx;
14   
15 uart_tx uart_tx_inst(
16    .clk(clk),
17    .rst_n(rst_n),
18    .send_en(send_en), 
19    .data_in(data_in),
20     .rs232_tx(rs232_tx)
21 );
22 
23 uart_rx uart_rx_inst(
24   .clk(clk),
25   .rst_n(rst_n),
26   .rs232_rx(rs232_tx),
27   .rx_done(rx_done),
28   .data_out(data_out)
29 );
30 
31 initial
32   clk = 1'b0;
33   always #10 clk = ~clk;
34   
35 initial
36   begin
37     send_en = 1'b0;
38      data_in = 8'h0;
39     rst_n = 1'b0;
40      #100;
41      rst_n = 1'b1;
42      
43      #100;
44      send_en = 1'b1;
45      data_in = 8'h55;
46      #20;
47      
48      #1000000;
49      
50      $stop;
51      
52   end
53 endmodule
54      
View Code

 回环测试代码:

 1 module uart_loop(
 2   input        clk,
 3   input        rst_n,
 4   input         rs232_rx,
 5   
 6   output        rs232_tx
 7 );
 8 
 9 wire en;
10 wire[7:0] data;
11 
12 uart_tx u0(
13   .clk        (clk           ),
14   .rst_n        (rst_n        ),
15   .send_en    (en           ),
16   .data_in    ( data        ),
17   .rs232_tx (rs232_tx     )
18 );
19 
20 uart_rx u1(
21   .clk        (clk            ),
22   .rst_n        (rst_n         ),
23   .rs232_rx    (rs232_rx     ),
24   .rx_done    (en              ),
25   .data_out    ( data          )
26 );
27 
28 endmodule
View Code

 回环测试效果:

原文地址:https://www.cnblogs.com/571328401-/p/12500763.html