当前位置:   article > 正文

Verilog UART串口详解(代码及整体思路)_uart verilog

uart verilog

目录

一、uart概述

二、uart数据格式

2.1 uart起始位的意义

2.2 停止位的意义

2.3 UART基本的数据形式

2.4 UART的数据位可变

三、uart的波特率

四、Verilog 模块划分

五、发送模块(TX)

5.1 发送模块状态跳变

5.2 Verilog 设计文件

5.3 仿真文件

5.4 测试结果

5.5 上板测试(tx_text)

六、接收模块(rx)

6.1 接收模块状态跳转

6.2 接收模块  Verilog 设计文件

6.3 仿真文件

6.5 上板测验(加入tx模块的串口回环)

七、uart_ctrl模块(fifo)

7.1 引入fifo作为数据缓冲器的意义

7.2 fifo IP的配置

7.3 uart_ctrl 设计文件

八、顶层整合

8.1 top文件

8.2 整体仿真

8.2.2 仿真波形分析

九、 上板检测


一、uart概述

UART的全称是通用异步收发器(Universal Asynchronous Receiver/Transmitter)

UART是一个通用的接口协议,被广泛的应用在各类MCU和SOC产品上。“不需要额外的时钟线进行数据的同步传输”,只要信号拉低,就可开始传送数据。UART 只需要两条信号线:RXDTXD(一个数据的发送方和一个数据的接收方 ),其中 RXD 是 UART 的接收端TXD 是 UART 的发送端,接收与发送是全双工形式。

它可以和各种标准串行接口,如 RS 232 和 RS 485 等进行全双工异步通信, 具有传输距离远、成本低、可靠性高等优点。一般 UART 由专用芯片如: 8250, 16450 来实现,但专用芯片引脚都较多,内含许多辅助功能,在实际使用时往往只需要用到 UART 的基本功能,使用专用芯片会造成资源浪费和成本提高。

二、uart数据格式

UART的一帧由四部分组成起始位(1bit)数据位(6\7\8bit)校验位(1bit)停止位(1\1.5\2bit),如下图所示,

uart 是将传输数据的每个字符一位接一位地传输。 其中每一位(Bit)的意义如下:

空闲位:高电平,表明当前无传输事务。

起始位:一位低电平信号,标志着数据传输的开始。

数据位:紧接着起始位之后。数据位的个数可以是 6、7、8 等,构 成一个字符。通常采用 ASCII 码。从最低位开始传送,依靠时钟定位。

奇偶校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或 奇数(奇校验),以此来校验数据传送的正确性。

停止位:一个字符数据的结束标志。可以是 1 位、1.5 位、2 位的高电平。

由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通 信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束, 并且提供计算机校正时钟同步的机会。停止位的位数越多,不同时钟同步的容 忍程度越大,但是数据传输率同时也越慢。

2.1 uart起始位的意义

因为UART没有控制线,要让接收方知道什么时候开始接收数据,需要一些手段,UART数据的传输中,只有一根线,所以在发送数据之前,先发一位逻辑“0”作为数据发送的起始标志,接收方在空闲时,当检测到有一个低电平,则开始接逐位接收数据。

2.2 停止位的意义

因为通信两个机器之间不可避免的存在时钟偏移,为了消除数据交互之间时钟偏移对数据传输产生的影响,所以在每一次数据发送结束后,要发送一位逻辑“1”作为数据发送的结束标志,接收方在空闲时,当检测到有一个高电平,则结束接收一次数据。

2.3 UART基本的数据形式

  • 默认无传输数据时,为高电平

  • 当信号拉低,传输线上的电平拉低,意味着开始进行数据传输

  • 紧接着起始位的是数据位,它可以是5、6、7或8位

  • UART的“校验位”紧挨着“数据位”,采用奇偶校验方式,根据设置,校验位可以存在也可以不存在

  • UART将停止位作为停止标志,是在数据位(没有校验位)和校验位(有校验位)之后发送1~2位的逻辑“1”高电平。当发送完停止位之后,UART总线进入空闲。

2.4 UART的数据位可变

因为UART是一种低速总线,每多发一位都占用不少的时间(由传输波特率决定),所以可以根据传输数据的特点,采用不同位宽以节约数据传输的时间

三、uart的波特率

波特率等于每秒钟传输的数据位数

常用的波特率有:9600、19200、38400、57600、115200,本工程所用到的是115200。

计算传输1bit需要的时间如下表:假如我们的全局时钟频率为100MHz,波特率设置为9600,那么意味着每秒该UART传输协议可以传输9600bits的数据。传输1比特需时间约为:10^9(ns)/9600=104166(ns)。

四、Verilog 模块划分

uart 的设计分为两个部分,一部分为发送模块,另一部分为接收模块。程 序设计主要通过状态机实现,系统框架图如下:

  • 全局参数

  1. parameter                   CHECK_BIT =  "None"     ,    //校验位   “None”无校验 “Odd”奇校验,“Even”偶校验
  2.    parameter                   BPS       =  115200     ,    //系统波特率
  3.    parameter                   CLK       =  50_000_000 ,    //系统时钟频率
  4.    parameter                   DATA_BIT  =  8           ,    //数据位(678
  5.    parameter                   STOP_BIT  =  1                //停止位

五、发送模块(TX)

5.1 发送模块状态跳变

IDLE:空闲状态,无数据传输,输出高电平,当tx_data_vld信号到来时跳转到START;

START:起始位,无数据传输,输出低电平为 ,无条件跳转至DATA;

DATA:数据位,进行数据传输,先发送低比特,根据数据输出高低电平,假如有校验位,跳到CHECK,假如数据传输不设校验位,跳转到STOP;

CHECK:奇偶校验位,

STOP:停止位,高电平,共 1 位。 发送模块在上一状态向下一状态切换时,改变电平

5.2 Verilog 设计文件

  1. /**************************************功能介绍***********************************
  2. Date : 202391821:37:53
  3. Author : linxiaoxiao.
  4. Version :
  5. Description: uart串口发送模块
  6. *********************************************************************************/
  7. //例化模版
  8. // tx_uart #(
  9. //     .CHECK_BIT ( "None"     ),   //校验位   “None”无校验 “Odd”奇校验,“Even”偶校验
  10. //     .BPS       ( 115200     ),   //系统波特率
  11. //     .CLK       ( 50_000_000 ),   //系统时钟频率
  12. //     .DATA_BIT ( 8           ),   //数据位(678
  13. //     .STOP_BIT ( 1           )     //停止位
  14. // )tx_uart_inst(
  15. //     /* input       */.clk   (),
  16. //     /* input       */.rst_n   (),
  17. //     /* input                       */.tx_data_vld (),
  18. //     /* input [DATA_BIT - 1:0]   */.tx_data     (),
  19. //     /* output                       */.tx_ready   (),
  20. //     /* output reg                 */.tx       ()
  21. // );
  22. //---------<模块及端口声名>------------------------------------------------------
  23. module tx_uart#(
  24.    parameter                   CHECK_BIT =  "None"     ,    //校验位   “None”无校验 “Odd”奇校验,“Even”偶校验
  25.    parameter                   BPS       =  115200     ,    //系统波特率
  26.    parameter                   CLK       =  50_000_000 ,    //系统时钟频率
  27.    parameter                   DATA_BIT  =  8           ,    //数据位(678
  28.    parameter                   STOP_BIT  =  1                //停止位
  29. )(
  30.    input        clk   ,
  31.    input        rst_n   ,
  32.    input                       tx_data_vld ,
  33.    input [DATA_BIT - 1:0]    tx_data     ,
  34.    output                      tx_ready   ,
  35.    output reg                 tx
  36. );
  37. //---------<参数定义>---------------------------------------------------------
  38. //波特计数最大值
  39.    localparam          BPS_MAX =   CLK/BPS;
  40. //状态机参数定义
  41.    localparam          IDLE    = 0 ,//
  42.                        START   = 1 ,//
  43.                        DATA    = 2 ,//
  44.                        CHECK   = 3 ,
  45.                        STOP    = 4 ;//
  46. //---------<内部信号定义>-----------------------------------------------------
  47.    reg [2:0]        state       ;//现态
  48.        
  49. //状态转移条件      
  50.    wire                    idle2start ;
  51.    wire                    start2data ;
  52.    wire                    data2check ;
  53.    wire                    data2stop   ;
  54.    wire                    check2stop ;
  55.    wire                    stop2idle   ;
  56.        
  57.    reg  [25:0]        bps_cnt   ;
  58.    wire        add_bps_cnt ,
  59.                            end_bps_cnt ;
  60.    reg  [3:0]            bit_cnt   ,
  61.                            BIT_MAX     ;
  62.    wire        add_bit_cnt ,
  63.                            end_bit_cnt ;
  64.    reg  [DATA_BIT - 1:0]  tx_data_r   ;
  65.    wire                   check_vld   ;//校验位使能
  66. /****************************************************************
  67.                    数据校验
  68. ****************************************************************/  
  69. //奇校验缩位同或
  70. /*         assign     check_vld = ~^tx_data_r; */
  71. //偶校验缩位异或
  72. /* assign       check_vld = ^tx_data_r; */
  73. assign     check_vld = (CHECK_BIT == "Odd")?~^tx_data_r:^tx_data_r;
  74. /****************************************************************
  75.                    输入数据寄存
  76. ****************************************************************/
  77.    always @(posedge clk or negedge rst_n)
  78.        if(!rst_n)
  79.            tx_data_r <= 'd0;
  80.        else if(tx_data_vld)
  81.            tx_data_r <= tx_data;
  82. /****************************************************************
  83.                    fsm
  84. ****************************************************************/
  85. // 时序逻辑描述状态转移
  86. always @(posedge clk or negedge rst_n)begin
  87.    if(!rst_n)begin
  88.        state <= IDLE;
  89.    end
  90.    else case(state)
  91.            IDLE   : if(idle2start) state <= START;  
  92.            START   : if(start2data) state <= DATA ;  
  93.            DATA   : if(data2check) state <= CHECK;
  94.                else  if(data2stop ) state <= STOP ;  
  95.            CHECK   : if(check2stop) state <= STOP ;    
  96.            STOP   : if(stop2idle ) state <= IDLE ;    
  97.            default : state <= IDLE ;
  98.        endcase
  99.    end
  100.              
  101.    assign    idle2start = state == IDLE  && tx_data_vld;
  102.    assign    start2data = state == START && end_bit_cnt;
  103.    assign    data2check = state == DATA  && end_bit_cnt && CHECK_BIT != "None";
  104.    assign    data2stop  = state == DATA  && end_bit_cnt && CHECK_BIT == "None";
  105.    assign    check2stop = state == CHECK && end_bit_cnt;
  106.    assign    stop2idle  = state == STOP  && end_bit_cnt;    
  107. /****************************************************************
  108.                bps_cnt                    
  109. ****************************************************************/
  110.    always @(posedge clk or negedge rst_n)begin
  111.       if(!rst_n)begin
  112.            bps_cnt <= 'd0;
  113.        end
  114.        else if(add_bps_cnt)begin
  115.            if(end_bps_cnt)begin
  116.                bps_cnt <= 'd0;
  117.            end
  118.            else begin
  119.                bps_cnt <= bps_cnt + 1'b1;
  120.            end
  121.        end
  122.    end
  123.    
  124.    assign add_bps_cnt = state != IDLE;
  125.    assign end_bps_cnt = add_bps_cnt && bps_cnt == BPS_MAX - 1;
  126. /****************************************************************
  127.                    bit_cnt
  128. ****************************************************************/      
  129.    always @(posedge clk or negedge rst_n)begin
  130.       if(!rst_n)begin
  131.            bit_cnt <= 'd0;
  132.        end
  133.        else if(add_bit_cnt)begin
  134.            if(end_bit_cnt)begin
  135.                bit_cnt <= 'd0;
  136.            end
  137.            else begin
  138.                bit_cnt <= bit_cnt + 1'b1;
  139.            end
  140.        end
  141.    end
  142.    
  143.    assign add_bit_cnt = end_bps_cnt;
  144.    assign end_bit_cnt = add_bit_cnt && bit_cnt == BIT_MAX - 1;
  145. //计数器复用
  146.    always @(*)begin
  147.       case (state)
  148.        START : BIT_MAX = 1;
  149.        DATA   : BIT_MAX = DATA_BIT;
  150.        CHECK : BIT_MAX = 1;
  151.        STOP   : BIT_MAX = STOP_BIT;
  152.        default: BIT_MAX = 1;
  153.       endcase
  154.    end
  155. /****************************************************************
  156.                    tx时序
  157. ****************************************************************/
  158.    always @(*)begin
  159.        case (state)
  160.            IDLE   :   tx = 1;
  161.            START   :   tx = 0;
  162.            DATA   :   if(tx_data_r[bit_cnt])  tx= 1;
  163.                        else tx = 0;
  164.            CHECK   :   tx = check_vld;
  165.            STOP   :   tx = 1;
  166.            default :   tx = 1;
  167.        endcase
  168.    end
  169.    assign      tx_ready = state == IDLE;
  170.    
  171. endmodule

5.3 仿真文件

  1. `timescale 1ns/1ns
  2.    
  3. module tx_tb();
  4. //激励信号定义
  5.    reg tb_clk ;
  6.    reg tb_rst_n ;
  7.    reg    [7:0]   tx_data ;
  8.    reg             tx_data_vld ;
  9. //输出信号定义
  10.    wire        tx     ;
  11.  
  12. //时钟周期参数定义
  13.    parameter CLOCK_CYCLE = 20;  
  14. //模块例化
  15. tx_uart #(
  16.     .CHECK_BIT ( "None"      ),    //校验位   “None”无校验 “Odd”奇校验,“Even”偶校验
  17.     .BPS       ( 115200      ),    //系统波特率
  18.     .CLK       ( 50_000_000  ),    //系统时钟频率
  19.     .DATA_BIT  ( 8           ),    //数据位(678
  20.     .STOP_BIT  ( 1           )     //停止位
  21. )tx_uart_inst(
  22.     /* input       */.clk   (tb_clk ),
  23.     /* input       */.rst_n   (tb_rst_n ),
  24.     /* input                       */.tx_data_vld (tx_data_vld ),
  25.     /* input [DATA_BIT - 1:0]   */.tx_data     (tx_data     ),
  26.     /* output                     */.tx_ready    (tx_ready    ),
  27.     /* output reg                 */.tx       (tx        )
  28. );
  29. //产生时钟
  30.    initial tb_clk = 1'b0;
  31.    always #(CLOCK_CYCLE/2) tb_clk = ~tb_clk;
  32. //复位
  33.    initial  begin
  34.        tb_rst_n = 1'b1;
  35.        #(CLOCK_CYCLE*2);
  36.        tb_rst_n = 1'b0;
  37.        #(CLOCK_CYCLE*20);
  38.        tb_rst_n = 1'b1;
  39.    end
  40. integer i;
  41. //描述输入
  42.    initial begin
  43.        #(CLOCK_CYCLE*200);
  44.        #1;
  45.        tx_data     = 0;
  46.        tx_data_vld = 0;
  47.        #(CLOCK_CYCLE*4);
  48.    for ( i= 0;i<10 ;i=i+1 ) begin
  49.        #(CLOCK_CYCLE*20);
  50.        tx_data_vld = 1;
  51.        tx_data = {$random}%256;
  52.        #20;
  53.        tx_data_vld = 0;
  54.        wait(tx_uart_inst.stop2idle == 1);
  55.    end  
  56.        
  57.        #100800;
  58.        $stop;
  59.    end
  60. endmodule

5.4 测试结果

模拟多次数据传输:

放大:

5.5 上板测试(tx_text)

这里引入一个按键消抖模块作为接收使能,检验代码如下:

  1. /**************************************功能介绍***********************************
  2. Date :
  3. Author : linxiaoxiao.
  4. Version :
  5. Description: 测试tx模块
  6. *********************************************************************************/
  7.    
  8. //---------<模块及端口声名>------------------------------------------------------
  9. module tx_text(
  10.    input clk ,
  11.    input rst_n ,
  12.    input               key_in ,
  13.    
  14.    output        tx
  15. );
  16.    
  17. //---------<内部信号定义>-----------------------------------------------------
  18.    wire                key_down;
  19.    
  20. //模块例化
  21.    tx_uart #(
  22.   .CHECK_BIT ( "None"      ),    //校验位   “None”无校验 “Odd”奇校验,“Even”偶校验
  23.   .BPS       ( 115200      ),    //系统波特率
  24.   .CLK       ( 50_000_000  ),    //系统时钟频率
  25.   .DATA_BIT  ( 8           ),    //数据位(678
  26.   .STOP_BIT  ( 1           )     //停止位
  27. )tx_uart_inst(
  28.    /* input       */.clk   ( clk    ),
  29.    /* input       */.rst_n   ( rst_n        ),
  30.    /* input                       */.tx_data_vld ( key_down       ),
  31.    /* input [DATA_BIT - 1:0]   */.tx_data     ( 8'hac          ),
  32.    /* output                       */.tx_ready    ( tx_ready       ),
  33.    /* output reg                 */.tx       ( tx            )
  34. );
  35.    
  36. fsm_key_filter  #( .WIDTH(1))  fsm_key_filter_inst (
  37.   /* input       */.clk   ( clk  ),
  38.   /* input       */.rst_n   ( rst_n  ),
  39.   /* input   [WIDTH-1:0] */.key_in   ( key_in   ),
  40.   /* output reg   [WIDTH-1:0]*/.key_down ( key_down )    
  41. );    
  42.    
  43.    
  44. endmodule

配置引脚

  1. #引脚参数导入脚本
  2. #时钟、复位
  3. set_location_assignment PIN_E1 -to clk
  4. set_location_assignment PIN_E15 -to rst_n
  5. #UART
  6. #set_location_assignment PIN_M2 -to uart_rx
  7. set_location_assignment PIN_G1 -to tx

串口窗口 可设置奇偶校验

六、接收模块(rx)

6.1 接收模块状态跳转

IDLE:空闲状态,无数据传输,输出高电平,当tx_data_vld信号到来时跳转到START;  

START:起始位,无数据传输,输出低电平为 ,延时结束后至DATA; 

DATA:数据位,进行数据传输,先发送低比特,根据数据输出高低电平,假如有校验位,跳到CHECK,假如数据传输不设校验位,跳转到STOP;  

CHECK:奇偶校验位

STOP:停止位,高电平,共 1 位。  发送模块在上一状态向下一状态切换时,改变电平

6.2 接收模块  Verilog 设计文件

  1. /**************************************功能介绍***********************************
  2. Date : 202391822:37:53
  3. Author : linxiaoxiao.
  4. Version :
  5. Description: uart串口接收模块
  6. *********************************************************************************/
  7. //例化模版
  8. // rx_uart #(
  9. // .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  10. // .BPS ( 115200 ), //系统波特率
  11. // .CLK ( 50_000_000 ), //系统时钟频率
  12. // .DATA_BIT ( 8 ), //数据位(678
  13. // .STOP_BIT ( 1 ) //停止位
  14. // )rx_uart_inst(
  15. // /* input */ .clk (),
  16. // /* input */ .rst_n (),
  17. // /* input reg */ .rx (),
  18. // /* output */ .rx_data_vld (),
  19. // /* output [DATA_BIT - 1:0] */ .rx_data (),
  20. // /* output */ .rx_ready ()
  21. // // );
  22. //---------<模块及端口声名>------------------------------------------------------
  23. module rx_uart#(
  24. parameter CHECK_BIT = "None" , //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  25. parameter BPS = 115200 , //系统波特率
  26. parameter CLK = 50_000_000 , //系统时钟频率
  27. parameter DATA_BIT = 8 , //数据位(678
  28. parameter STOP_BIT = 1 //停止位
  29. )(
  30. input clk ,
  31. input rst_n ,
  32. input rx ,
  33. output rx_data_vld ,
  34. output [DATA_BIT - 1:0] rx_data ,
  35. output rx_ready
  36. );
  37. //---------<参数定义>---------------------------------------------------------
  38. //波特计数最大值
  39. localparam BPS_MAX = CLK/BPS;
  40. //状态机参数定义
  41. localparam IDLE = 0 ,//空闲
  42. START = 1 ,//起始位
  43. DATA = 2 ,//数据位
  44. CHECK = 3 ,//奇偶校验位
  45. STOP = 4 ;//停止位
  46. //---------<内部信号定义>-----------------------------------------------------
  47. reg [2:0] state ;//现态
  48. //状态转移条件
  49. wire idle2start ;
  50. wire start2data ;
  51. wire data2check ;
  52. wire data2stop ;
  53. wire check2stop ;
  54. wire stop2idle ;
  55. reg [25:0] bps_cnt ;
  56. wire add_bps_cnt ,
  57. end_bps_cnt ;
  58. reg [3:0] bit_cnt ,
  59. BIT_MAX ;
  60. wire add_bit_cnt ,
  61. end_bit_cnt ;
  62. reg [DATA_BIT - 1:0] temp_data ;//输入数据零时缓存
  63. reg check_reg ;//校验寄存
  64. wire check_vld ;//校验位使能
  65. reg rx_r0 ,//输入数据同步寄存
  66. rx_r1 ;
  67. wire flag_n ;//下降沿监测 确定rx采样时序
  68. /****************************************************************
  69. 输入数据寄存(同步打拍)
  70. ****************************************************************/
  71. always @(posedge clk or negedge rst_n)begin
  72. if(!rst_n)begin
  73. rx_r0 <= 0;
  74. rx_r1 <= 0;
  75. end
  76. else begin
  77. rx_r0 <= rx;
  78. rx_r1 <= rx_r0;
  79. end
  80. end
  81. //下降沿标志
  82. assign flag_n = !rx_r0 && rx_r1;
  83. /****************************************************************
  84. 数据接收逻辑
  85. ****************************************************************/
  86. always @(posedge clk or negedge rst_n)
  87. if(!rst_n)
  88. temp_data <= 'd0;
  89. else if(state == DATA && bps_cnt == BPS_MAX >> 1)
  90. temp_data[bit_cnt] <= rx_r0;
  91. /****************************************************************
  92. 接收数据校验
  93. ****************************************************************/
  94. always @(posedge clk or negedge rst_n)
  95. if(!rst_n)
  96. check_reg <= 'd0;
  97. else if(state == CHECK && bps_cnt == BPS_MAX >> 1)
  98. check_reg <= rx_r0;
  99. //校验位选择
  100. assign check_vld = (CHECK_BIT == "Odd")?~^temp_data : ^temp_data;
  101. /****************************************************************
  102. fsm
  103. ****************************************************************/
  104. // 时序逻辑描述状态转移
  105. always @(posedge clk or negedge rst_n)begin
  106. if(!rst_n)begin
  107. state <= IDLE;
  108. end
  109. else case(state)
  110. IDLE : if(idle2start) state <= START;
  111. START : if(start2data) state <= DATA ;
  112. DATA : if(data2check) state <= CHECK;
  113. else if(data2stop ) state <= STOP ;
  114. CHECK : if(check2stop) state <= STOP ;
  115. STOP : if(stop2idle ) state <= IDLE ;
  116. default : state <= IDLE ;
  117. endcase
  118. end
  119. assign idle2start = state == IDLE && flag_n ;
  120. assign start2data = state == START && end_bit_cnt;
  121. assign data2check = state == DATA && end_bit_cnt && CHECK_BIT != "None";
  122. assign data2stop = state == DATA && end_bit_cnt && CHECK_BIT == "None";
  123. assign check2stop = state == CHECK && end_bit_cnt;
  124. assign stop2idle = state == STOP && end_bit_cnt;
  125. /****************************************************************
  126. bps_cnt
  127. ****************************************************************/
  128. always @(posedge clk or negedge rst_n)begin
  129. if(!rst_n)begin
  130. bps_cnt <= 'd0;
  131. end
  132. else if(add_bps_cnt)begin
  133. if(end_bps_cnt)begin
  134. bps_cnt <= 'd0;
  135. end
  136. else begin
  137. bps_cnt <= bps_cnt + 1'b1;
  138. end
  139. end
  140. end
  141. assign add_bps_cnt = state != IDLE;
  142. assign end_bps_cnt = add_bps_cnt && bps_cnt == BPS_MAX - 1;
  143. /****************************************************************
  144. bit_cnt
  145. ****************************************************************/
  146. always @(posedge clk or negedge rst_n)begin
  147. if(!rst_n)begin
  148. bit_cnt <= 'd0;
  149. end
  150. else if(add_bit_cnt)begin
  151. if(end_bit_cnt)begin
  152. bit_cnt <= 'd0;
  153. end
  154. else begin
  155. bit_cnt <= bit_cnt + 1'b1;
  156. end
  157. end
  158. end
  159. assign add_bit_cnt = end_bps_cnt;
  160. assign end_bit_cnt = add_bit_cnt && bit_cnt == BIT_MAX - 1;
  161. //计数器复用
  162. always @(*)begin
  163. case (state)
  164. START : BIT_MAX = 1;
  165. DATA : BIT_MAX = DATA_BIT;
  166. CHECK : BIT_MAX = 1;
  167. STOP : BIT_MAX = STOP_BIT;
  168. default: BIT_MAX = 1;
  169. endcase
  170. end
  171. /****************************************************************
  172. 输出逻辑
  173. ****************************************************************/
  174. assign rx_ready = state == IDLE;
  175. assign rx_data_vld = (CHECK_BIT == "None")? stop2idle
  176. : (stop2idle && (check_vld == check_reg))? 1
  177. : 0;
  178. assign rx_data =(state == STOP && bit_cnt == STOP_BIT - 1) ? temp_data : 'b0 ;
  179. endmodule

6.3 仿真文件

两种模拟输入方式,都在下面体现了:

  1. `timescale 1ns/1ns
  2. module rx_tb ();
  3. //激励信号定义
  4. reg clk ;
  5. reg rst_n ;
  6. reg /* tx_data_vld , */rx_din;
  7. /* reg [7:0] tx_data ; */
  8. /* wire tx ; */
  9. //输出信号定义
  10. wire /* tx_ready , */rx_data_vld ;
  11. //时钟周期参数定义
  12. parameter CLOCK_CYCLE = 20;
  13. //模块例化
  14. // tx_uart #(
  15. // .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  16. // .BPS ( 115200 ), //系统波特率
  17. // .CLK ( 50_000_000 ), //系统时钟频率
  18. // .DATA_BIT ( 8 ), //数据位(678
  19. // .STOP_BIT ( 1 ) //停止位
  20. // )tx_uart_inst(
  21. // /* input */.clk (clk ),
  22. // /* input */.rst_n (rst_n ),
  23. // /* input */.tx_data_vld (tx_data_vld ),
  24. // /* input [DATA_BIT - 1:0] */.tx_data (tx_data ),
  25. // /* output */.tx_ready (tx_ready ),
  26. // /* output reg */.tx (tx )
  27. // );
  28. rx_uart #(
  29. .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  30. .BPS ( 115200 ), //系统波特率
  31. .CLK ( 50_000_000 ), //系统时钟频率
  32. .DATA_BIT ( 8 ), //数据位(678
  33. .STOP_BIT ( 1 ) //停止位
  34. )rx_uart_inst(
  35. /* input */ .clk ( clk ),
  36. /* input */ .rst_n ( rst_n ),
  37. /* input reg */ .rx ( rx_din ),
  38. /* output */ .rx_data_vld ( rx_data_vld ),
  39. /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
  40. /* output */ .rx_ready ( rx_ready )
  41. );
  42. //产生时钟
  43. initial clk = 1'b0;
  44. always #(CLOCK_CYCLE/2) clk = ~clk;
  45. //产生激励
  46. initial begin
  47. rst_n = 1'b1;
  48. #(CLOCK_CYCLE*2);
  49. rst_n = 1'b0;
  50. #(CLOCK_CYCLE*20);
  51. rst_n = 1'b1;
  52. end
  53. initial begin
  54. repeat(5)begin
  55. rx_din = 1'b1;
  56. #(20*100)
  57. rx_din = 1'b0;
  58. #(434*20)
  59. repeat(8)begin
  60. rx_din = {$random};
  61. #(434*20);
  62. end
  63. rx_din = 1'b1;
  64. wait(rx_data_vld == 1);
  65. end
  66. #10000;
  67. $stop;
  68. // tx_data = 0;
  69. // tx_data_vld = 0;
  70. // #(CLOCK_CYCLE*6);
  71. // tx_data_vld = 1;
  72. // repeat(8) begin
  73. // tx_data = {$random};#20;
  74. // tx_data_vld = 0;
  75. // #200;
  76. // tx_data_vld = 1;
  77. // wait(tx_ready == 1);
  78. // #20;
  79. // end
  80. // #20000000;
  81. // $stop;
  82. end
  83. endmodule

6.5 上板测验(加入tx模块的串口回环)

代码:

  1. /**************************************功能介绍***********************************
  2. Date :
  3. Author : linxiaoxiao.
  4. Version :
  5. Description: 串口回环(未加fifo)
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module top(
  9. input clk ,
  10. input rst_n ,
  11. input rx ,
  12. output tx
  13. );
  14. //---------<内部信号定义>-----------------------------------------------------
  15. wire [7:0] rx_data ;
  16. wire tx_ready ;
  17. wire rx_data_vld;
  18. //模块例化
  19. tx_uart #(
  20. .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  21. .BPS ( 115200 ), //系统波特率
  22. .CLK ( 50_000_000 ), //系统时钟频率
  23. .DATA_BIT ( 8 ), //数据位(678
  24. .STOP_BIT ( 1 ) //停止位
  25. )tx_uart_inst(
  26. /* input */.clk ( clk ),
  27. /* input */.rst_n ( rst_n ),
  28. /* input */.tx_data_vld ( rx_data_vld && tx_ready ),
  29. /* input [DATA_BIT - 1:0] */.tx_data ( rx_data ),
  30. /* output */.tx_ready ( tx_ready ),
  31. /* output reg */.tx ( tx )
  32. );
  33. rx_uart #(
  34. .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  35. .BPS ( 115200 ), //系统波特率
  36. .CLK ( 50_000_000 ), //系统时钟频率
  37. .DATA_BIT ( 8 ), //数据位(678
  38. .STOP_BIT ( 1 ) //停止位
  39. )rx_uart_inst(
  40. /* input */ .clk ( clk ),
  41. /* input */ .rst_n ( rst_n ),
  42. /* input reg */ .rx ( rx ),
  43. /* output */ .rx_data_vld ( rx_data_vld ),
  44. /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
  45. /* output */ .rx_ready ( rx_ready )
  46. );
  47. endmodule

七、uart_ctrl模块(fifo)

7.1 引入fifo作为数据缓冲器的意义

在串口通信中,采用缓冲器FIFO的主要意义是解决数据传输中的**时序差异**问题,并提供数据的缓冲和流控能力。具体而言,它有以下几个作用:

1. 时序匹配:串口通信中发送方和接收方的时钟频率可能存在差异,使用FIFO可以将数据以一定的速率存储在缓冲区中,从而实现发送方和接收方之间的时序匹配,避免数据的丢失和错误。

2. 数据缓冲:在数据传输中,当发送方产生数据的速率快于接收方处理数据的速率时,FIFO可以暂时存储多出来的数据,保证数据不会丢失。

3. 流控控制:当接收方处理能力不足以处理发送方的数据时,FIFO可以用于流控,即发送方通过监测FIFO的状态来控制数据的发送速率,从而避免数据的丢失。

4. 缓存传输:一些应用场景中,需要在某个特定时刻对数据进行处理,而不是即时处理。FIFO可以将接收到的数据缓存在缓冲区中,待到特定时刻再进行处理。

总之,**FPGA串口数据缓冲器FIFO在数据传输中起到了时序匹配、数据缓冲、流控控制和缓存传输的重要作用,提高了数据传输的可靠性和灵活性。**

7.2 fifo IP的配置

7.3 uart_ctrl 设计文件

  1. /**************************************功能介绍***********************************
  2. Date : 202392121:48:59
  3. Author : linxiaoxiao.
  4. Version :
  5. Description: uart_ctrl控制模块——fifo
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module uart_ctrl(
  9. input clk ,
  10. input rst_n ,
  11. input [7:0] rx_data ,
  12. input rx_data_vld ,
  13. input tx_ready ,
  14. output [7:0] tx_data ,
  15. output tx_data_vld
  16. );
  17. //---------<内部信号定义>-----------------------------------------------------
  18. wire fifo_empty ;
  19. wire fifo_full ;
  20. fifo fifo_inst (
  21. .aclr ( ~rst_n ),
  22. .clock ( clk ),
  23. .data ( rx_data ),
  24. .rdreq ( ~fifo_empty && tx_ready ),
  25. .wrreq ( rx_data_vld && ~fifo_full ),
  26. .empty ( fifo_empty ),
  27. .full ( fifo_full ),
  28. .q ( tx_data ),
  29. .usedw ( )
  30. );
  31. assign tx_data_vld = tx_ready && ~fifo_empty ;
  32. endmodule

八、顶层整合

8.1 top文件

  1. /**************************************功能介绍***********************************
  2. Date :
  3. Author : linxiaoxiao.
  4. Version :
  5. Description:
  6. *********************************************************************************/
  7. //---------<模块及端口声名>------------------------------------------------------
  8. module top(
  9. input clk ,
  10. input rst_n ,
  11. input rx ,
  12. output tx
  13. );
  14. //---------<内部信号定义>-----------------------------------------------------
  15. wire [7:0] tx_data , rx_data ;
  16. wire tx_ready , rx_ready ;
  17. wire tx_data_vld,rx_data_vld;
  18. //模块例化
  19. tx_uart #(
  20. .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  21. .BPS ( 115200 ), //系统波特率
  22. .CLK ( 50_000_000 ), //系统时钟频率
  23. .DATA_BIT ( 8 ), //数据位(678
  24. .STOP_BIT ( 1 ) //停止位
  25. )tx_uart_inst(
  26. /* input */.clk ( clk ),
  27. /* input */.rst_n ( rst_n ),
  28. /* input */.tx_data_vld ( tx_data_vld ),
  29. /* input [DATA_BIT - 1:0] */.tx_data ( tx_data ),
  30. /* output */.tx_ready ( tx_ready ),
  31. /* output reg */.tx ( tx )
  32. );
  33. uart_ctrl uart_ctrl_inst(
  34. /* input */.clk ( clk ),
  35. /* input */.rst_n ( rst_n ),
  36. /* input [7:0] */.rx_data ( rx_data ),
  37. /* input */.rx_data_vld ( rx_data_vld ),
  38. /* input */.tx_ready ( tx_ready ),
  39. /* output [7:0] */.tx_data ( tx_data ),
  40. /* output */.tx_data_vld ( tx_data_vld )
  41. );
  42. rx_uart #(
  43. .CHECK_BIT ( "None" ), //校验位 “None”无校验 “Odd”奇校验,“Even”偶校验
  44. .BPS ( 115200 ), //系统波特率
  45. .CLK ( 50_000_000 ), //系统时钟频率
  46. .DATA_BIT ( 8 ), //数据位(678
  47. .STOP_BIT ( 1 ) //停止位
  48. )rx_uart_inst(
  49. /* input */ .clk ( clk ),
  50. /* input */ .rst_n ( rst_n ),
  51. /* input reg */ .rx ( rx ),
  52. /* output */ .rx_data_vld ( rx_data_vld ),
  53. /* output [DATA_BIT - 1:0] */ .rx_data ( rx_data ),
  54. /* output */ .rx_ready ( rx_ready )
  55. );
  56. endmodule

8.2 整体仿真

8.2.1 仿真文件

  1. `timescale 1ns/1ns
  2. module tb_top ();
  3. //激励信号定义
  4. reg clk ;
  5. reg rst_n ;
  6. reg rx_din ;
  7. //时钟周期参数定义
  8. parameter CLOCK_CYCLE = 20;
  9. top top_inst(
  10. /* input */.clk ( clk ),
  11. /* input */.rst_n ( rst_n ),
  12. /* input */.rx ( rx_din ),
  13. /* output */.tx ( tx )
  14. );
  15. //产生时钟
  16. initial clk = 1'b0;
  17. always #(CLOCK_CYCLE/2) clk = ~clk;
  18. //产生激励
  19. initial begin
  20. rst_n = 1'b1;
  21. #(CLOCK_CYCLE*2);
  22. rst_n = 1'b0;
  23. #(CLOCK_CYCLE*20);
  24. rst_n = 1'b1;
  25. end
  26. initial begin
  27. repeat(5)begin
  28. rx_din = 1'b1;
  29. #(20*100)
  30. rx_din = 1'b0;
  31. #(434*20)
  32. repeat(8)begin
  33. rx_din = {$random};
  34. #(434*20);
  35. end
  36. rx_din = 1'b1;
  37. wait(top_inst.rx_uart_inst.rx_data_vld == 1);
  38. end
  39. #10000;
  40. $stop;
  41. end
  42. endmodule
8.2.2 仿真波形分析

九、 上板检测

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/641369
推荐阅读
相关标签
  

闽ICP备14008679号