• 基于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

     回环测试效果:

  • 相关阅读:
    display:inline、block、inline-block的区别
    CSS选择器优先级总结
    bootstarp模板01
    Vue深度学习(6)- 组件
    在Ubuntu下安装mongodb
    Ajax高级应用---Comet
    ubuntu安装
    linux使用
    跨浏览器的CORS
    防止伪造跨站请求
  • 原文地址:https://www.cnblogs.com/571328401-/p/12500763.html
Copyright © 2020-2023  润新知