【UART】Verilog实现UART接收和发送模块

发布时间:2026/5/20 4:11:48

【UART】Verilog实现UART接收和发送模块 目录写在前面UART 工作原理UART 接收部分UART RX 模块图UART RX 时序图Verilog 实现 UART RX 模块UART 发送部分UART TX 模块图UART TX 时序图Verilog 实现 UART TX 模块总结写在前面UART协议在之前的一篇博客中有介绍直达链接如下【总线】一文看懂 UART 通信协议这里只是做简单的介绍重点在 Verilog 实现部分。UART 工作原理将要传输数据的UART从数据总线接收数据。数据总线用于通过另一个设备如CPU内存或微控制器将数据发送到UART。数据以并行形式从数据总线传输到传输UART。在发送UART从数据总线获取并行数据后它会添加一个起始位、一个奇偶校验位和一个停止位从而创建数据包。接下来数据包在Tx引脚上逐位串行输出。接收UART在其Rx引脚上逐位读取数据包。然后接收的UART将数据转换回并行形式并删除起始位、奇偶校验位和停止位。最后接收UART将数据包并行传输到接收端的数据总线UART传输的数据被组织成数据包。每个数据包包含 1 个起始位、5 到 9 个数据位取决于 UART、一个可选的奇偶校验位以及 1 个或 2 个停止位UART 接收部分UART RX 模块图UART 接受模块的作用是将接受到的串行数据转换成并行数据。由于我做的实验工程是将 UART 和 RS485 共同使用所以需要一个信号 dir 控制RS485的传输方向如果不用 RS485 的话可以将此信号忽略。UART 的接受模块分为六个信号三个输入信号时钟信号clk、复位信号低有效rst_n、接受串行数据信号三个输出信号并行数据po_data、输出并行数据的同步标志信号pi_flag、控制方向信号 dir。UART RX 时序图时序图清晰的描述了数据是如何变化的。Verilog 实现 UART RX 模块timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Linest-5 // Create Date: 2022/04/14 // Design Name: // Module Name: UART_RX // Project Name: // Target Devices: // Tool Versions: // Description: UART 接收模块将串行的数据转成并行的数据接收 // Dependencies: // Revision: // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module UART_RX #( parameter BAUD_RATE d9600, //波特率 parameter CLK_FREQ d250000000, //时钟周期 parameter BAUD_CNT_MAX CLK_FREQ/BAUD_RATE ) ( input wire clk, //接收到的数据 input wire rst_n, //复位信号低电平有效 input wire rx, //输入的串行数据 output reg [7:0] po_data, //输出的并行数据 output reg po_flag //并行数据输出的同步标志信号 ); reg rx_reg1; //打三拍,稳定数据 reg rx_reg2; reg rx_reg3; reg start_flag; //数据稳定信号 reg work_en; //开始提取数据有效信号 reg bit_flag; //数据提取标志信号 reg [3:0] bit_cnt; //数据位计数信号 reg [12:0] baud_cnt; //比特计数信号一个数据需要多少个时钟周期 reg [7:0] rx_data; //串转并数据 reg rx_flag; //串转并完成信号 //消除亚稳态 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin rx_reg1 d1; end else begin rx_reg1 rx; end end always (posedge clk or negedge rst_n) begin if (rst_n d0) begin rx_reg2 d1; end else begin rx_reg2 rx_reg1; end end always (posedge clk or negedge rst_n) begin if (rst_n d0) begin rx_reg3 d1; end else begin rx_reg3 rx_reg2; end end //下降沿检测 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin start_flag d0; end else if ((rx_reg2 0) (rx_reg3 1) (work_en d0)) begin start_flag d1; end else begin start_flag d0; end end //开始数据计数信号 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin work_en d0; end else if (start_flag 1) begin work_en d1; end else if ((bit_flag 1) (bit_cnt d8)) begin work_en d0; end end //波特计数信号用时钟频率除以波特率即每个数据需要的时钟周期数 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin baud_cnt d0; end else if ((baud_cnt BAUD_CNT_MAX-1) || (work_en d0)) begin baud_cnt d0; end else begin baud_cnt baud_cnt d1; end end //数据中间提取最稳定 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin bit_flag d0; end else if (baud_cnt BAUD_CNT_MAX/2-1) begin bit_flag d1; end else begin bit_flag d0; end end //数据位计数信号只去有效的数据位起始位和结束位不要 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin bit_cnt d0; end else if ((bit_flag d1) (bit_cnt d8)) begin bit_cnt d0; end else if (bit_flag d1) begin bit_cnt bit_cnt d1; end end //将提取的数据串转并 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin rx_data d0; end else if ((bit_flag d1) (bit_cnt d1) (bit_cnt d8)) begin rx_data {rx_reg3,rx_data[7:1]}; end end //完成最后一个数据的拼接之后 就把此信号拉高 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin rx_flag d0; end else if ((bit_flag d1) (bit_cnt d8)) begin rx_flag d1; end else begin rx_flag d0; end end //并行数据输出 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin po_data d0; end else if (rx_flag d1) begin po_data rx_data; end else begin po_data po_data; end end //并行数据输出标志信号 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin po_flag d0; end else begin po_flag rx_flag; end end endmoduleUART 发送部分UART TX 模块图输入信号时钟信号clk、复位信号rst_n、输入并行数据、输入并行数据的同步标志信号输出信号发送串行数据tx、数据发送完成标志信号tx_done、方向控制信号dir、发哦是那个端空闲标志信号tx_readyUART TX 时序图Verilog 实现 UART TX 模块timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: Linest-5 // Create Date: 2022/04/15 // Design Name: // Module Name: UART_TX // Project Name: // Target Devices: // Tool Versions: // Description: UART 发送模块将接收到的并行数据转成串行数据并发送 // Dependencies: // Revision: // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module UART_TX( input clk, //系统时钟 input rst_n, //系统复位低电平有效 input valid, //数据有效信号 input [7:0] pi_data, //输入的并行数据 output tx, //并转串的输出数据 output tx_done, //并转串的输出数据发送完成标志信号 output reg dir1, //控制max3485的dir使能信号 output reg ready, //tx模块可以接收数据信号 output reg ena //使能信号 ); reg [7:0] pi_data_reg; //输入数据寄存 reg work_en; //开始提取数据有效信号 reg [17:0] baud_cnt; //波特计数信号每个数据需要的波特数 reg [3:0] bit_cnt; //数据位计数信号 reg bit_flag; //数据提取标志信号 reg tx_reg; //发送数据寄存 reg tx_done_reg; //发送数据完成标志信号 //参数定义 parameter CLK_FREQ d50000000; parameter BAUD_RATE d9600; parameter BAUD_CNT_MAX CLK_FREQ/BAUD_RATE; //检测输入数据的到来并将数据寄存 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin pi_data_reg d0; end else if (valid d1) begin pi_data_reg pi_data ; end else begin pi_data_reg pi_data_reg; end end //工作使能在数据标志信号为高时拉高在发送数据完成信号为高时拉低 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin work_en d0; end else if (valid d1) begin work_en d1; end else if (tx_done d1) begin work_en d0; end end //根据不同的波特率对每个数据需要波特数进行计数 always (posedge clk or negedge rst_n) begin if(rst_n d0)begin baud_cnt d0; end else if(work_en d1 (baud_cnt BAUD_CNT_MAX - d1))begin baud_cnt d0 ; end else if (work_en d1) begin baud_cnt baud_cnt d1 ; end else begin baud_cnt d0; end end //比特标志信号拉高在每一个波特计数为1时拉高相当于对数据的提取标志信号 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin bit_flag d0; end else if (baud_cnt d1) begin bit_flag d1; end else begin bit_flag d0; end end //比特计数信号在对每一个数据为进行计数 always (posedge clk or negedge rst_n) begin if(rst_n d0)begin bit_cnt d0; end else if ((work_en d1) (bit_flag d1) (bit_cnt d11)) begin bit_cnt d0; end else if ((work_en d1) (bit_flag d1)) begin bit_cnt bit_cnt d1; end else if (work_en d0) begin bit_cnt d0; end end //对并行数据映射到串行数据 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin tx_reg d0; end else begin case (bit_cnt) 4d1: tx_reg d0; 4d2: tx_reg pi_data_reg[0]; 4d3: tx_reg pi_data_reg[1]; 4d4: tx_reg pi_data_reg[2]; 4d5: tx_reg pi_data_reg[3]; 4d6: tx_reg pi_data_reg[4]; 4d7: tx_reg pi_data_reg[5]; 4d8: tx_reg pi_data_reg[6]; 4d9: tx_reg pi_data_reg[7]; 4d10:tx_reg d1; 4d11:tx_reg d1; default :tx_reg d1; endcase end end //发送数据完成标志信号 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin tx_done_reg d0; end else if ((bit_flag d1) (bit_cnt d10)) begin tx_done_reg d1; end else begin tx_done_reg d0; end end //在tx模块发送数据完成时或者空闲状态时拉高拉高表示可以接收上游传来的数据在数据并转串时拉低 always (posedge clk or negedge rst_n) begin if (rst_n d0) begin ready d1; end else if (tx_done d1) begin ready d1; end else if (valid d1) begin ready d0; end end //Bram的使能信号 always (posedge clk or negedge rst_n) begin if (rst_n) begin ena d0; end else begin ena tx_done; end end assign tx tx_reg; assign tx_done tx_done_reg; endmodule总结UART 的时序并不复杂最重要的是理解比特率的概念以及在计数当中如何设定这两个模块在实际的工程中可以正常跑通。

相关新闻