目录

写在前面

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) beginif (rst_n == 'd0) beginrx_reg1 <= 'd1;endelse beginrx_reg1 <= rx;endendalways @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginrx_reg2 <= 'd1;endelse beginrx_reg2 <= rx_reg1;endendalways @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginrx_reg3 <= 'd1;endelse beginrx_reg3 <= rx_reg2;endend//下降沿检测always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginstart_flag <= 'd0;endelse if ((rx_reg2 == 0) && (rx_reg3 == 1) && (work_en == 'd0)) begin start_flag <= 'd1;endelse beginstart_flag <= 'd0;endend//开始数据计数信号always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginwork_en <= 'd0;endelse if (start_flag == 1) beginwork_en <= 'd1;endelse if ((bit_flag == 1) && (bit_cnt == 'd8)) beginwork_en <= 'd0;endend//波特计数信号,用时钟频率除以波特率即每个数据需要的时钟周期数always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginbaud_cnt <= 'd0;endelse if ((baud_cnt == BAUD_CNT_MAX-1) || (work_en == 'd0)) beginbaud_cnt <= 'd0;endelse beginbaud_cnt <= baud_cnt + 'd1;endend//数据中间提取最稳定always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginbit_flag <= 'd0;endelse if (baud_cnt == BAUD_CNT_MAX/2-1) beginbit_flag <= 'd1;endelse beginbit_flag <= 'd0;endend//数据位计数信号,只去有效的数据位,起始位和结束位不要always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginbit_cnt <= 'd0;endelse if ((bit_flag == 'd1) && (bit_cnt == 'd8)) beginbit_cnt <= 'd0;endelse if (bit_flag == 'd1) beginbit_cnt <= bit_cnt + 'd1;endend//将提取的数据串转并always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginrx_data <= 'd0;endelse if ((bit_flag == 'd1) && (bit_cnt >= 'd1) && (bit_cnt <= 'd8)) beginrx_data <= {rx_reg3,rx_data[7:1]};endend//完成最后一个数据的拼接之后, 就把此信号拉高 always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginrx_flag <= 'd0;endelse if ((bit_flag == 'd1) && (bit_cnt == 'd8)) beginrx_flag <= 'd1;endelse beginrx_flag <= 'd0;endend//并行数据输出always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginpo_data <= 'd0;endelse if (rx_flag == 'd1) beginpo_data <= rx_data;endelse beginpo_data <= po_data;endend//并行数据输出标志信号always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginpo_flag <= 'd0;endelse beginpo_flag <= rx_flag;endendendmodule

UART 发送部分

UART TX 模块图

输入信号:时钟信号clk、复位信号rst_n、输入并行数据、输入并行数据的同步标志信号

输出信号:发送串行数据tx、数据发送完成标志信号tx_done、方向控制信号dir、发哦是那个端空闲标志信号tx_ready

UART 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     dir=1,                 //控制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) beginif (rst_n == 'd0) beginpi_data_reg <= 'd0;endelse if (valid == 'd1) beginpi_data_reg <= pi_data ;endelse beginpi_data_reg <= pi_data_reg;endend//工作使能,在数据标志信号为高时拉高,在发送数据完成信号为高时拉低always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginwork_en <= 'd0;endelse if (valid == 'd1) begin work_en <= 'd1;endelse if (tx_done == 'd1) beginwork_en <= 'd0;endend//根据不同的波特率,对每个数据需要波特数进行计数always @(posedge clk or negedge rst_n) beginif(rst_n == 'd0)beginbaud_cnt <= 'd0;endelse if(work_en == 'd1 && (baud_cnt == BAUD_CNT_MAX - 'd1))beginbaud_cnt <= 'd0 ;endelse if (work_en == 'd1) beginbaud_cnt <= baud_cnt + 'd1 ; endelse beginbaud_cnt <= 'd0;endend//比特标志信号拉高,在每一个波特计数为1时拉高,相当于对数据的提取标志信号always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginbit_flag <= 'd0;endelse if (baud_cnt == 'd1) beginbit_flag <= 'd1;endelse beginbit_flag <= 'd0;endend//比特计数信号,在对每一个数据为进行计数always @(posedge clk or negedge rst_n) beginif(rst_n == 'd0)beginbit_cnt <= 'd0;endelse if ((work_en == 'd1) && (bit_flag == 'd1) && (bit_cnt == 'd11)) beginbit_cnt <= 'd0;                       endelse if ((work_en == 'd1) && (bit_flag == 'd1)) beginbit_cnt <= bit_cnt + 'd1;endelse if (work_en == 'd0) beginbit_cnt <= 'd0;endend//对并行数据映射到串行数据always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) begintx_reg <= 'd0;endelse begincase (bit_cnt)4'd1: tx_reg <= 'd0;4'd2: tx_reg <= pi_data_reg[0];4'd3: tx_reg <= pi_data_reg[1];4'd4: tx_reg <= pi_data_reg[2];4'd5: tx_reg <= pi_data_reg[3];4'd6: tx_reg <= pi_data_reg[4];4'd7: tx_reg <= pi_data_reg[5];4'd8: tx_reg <= pi_data_reg[6];4'd9: tx_reg <= pi_data_reg[7];4'd10:tx_reg <= 'd1;4'd11:tx_reg <= 'd1;default :tx_reg <= 'd1; endcaseendend//发送数据完成标志信号always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) begintx_done_reg <= 'd0;endelse if ((bit_flag == 'd1) && (bit_cnt == 'd10)) begintx_done_reg <= 'd1;endelse begintx_done_reg <= 'd0;endend//在tx模块发送数据完成时或者空闲状态时拉高,拉高表示可以接收上游传来的数据,在数据并转串时拉低always @(posedge clk or negedge rst_n) beginif (rst_n == 'd0) beginready <= 'd1;endelse if (tx_done == 'd1) beginready <= 'd1;endelse if (valid == 'd1) beginready <= 'd0;endend//Bram的使能信号always @(posedge clk or negedge rst_n) beginif (rst_n) beginena <= 'd0;endelse beginena <= tx_done;endendassign tx = tx_reg;assign tx_done = tx_done_reg;endmodule

总结

UART 的时序并不复杂,最重要的是理解比特率的概念,以及在计数当中如何设定,这两个模块在实际的工程中可以正常跑通。

【UART】Verilog实现UART接收和发送模块相关推荐

  1. 基于FPGA实现uart串口模块(Verilog)--------发送模块及整合

    基于FPGA实现uart串口模块(Verilog)--------发送模块及整合 当接收模块接收到数据后,需要重新发送形成回环验证模块正确性.思路和结束模块有一点点的小差异.接收模块最终输出的是一个并 ...

  2. UART串口发送模块设计Verilog

    1.知识点 1.1 UART通信协议实现 定义 UART (Universal Asynchronous Receiver and Transmitter)即通用异步接收发送器,是一种通用的串行数据总 ...

  3. (58)UART外设驱动用户发送模块(三)(第12天)

    (58)UART外设驱动用户发送模块(三)(第12天) 1 文章目录 1)文章目录 2)FPGA初级课程介绍 3)FPGA初级课程架构 4)UART外设驱动用户发送模块(三)(第12天) 5)技术交流 ...

  4. (47)Verilog HDL UART接收设计

    (47)Verilog HDL UART接收设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL UART接收设计 5)结语 1.2 FPGA简介 ...

  5. (48)Verilog HDL UART发送设计

    (48)Verilog HDL UART发送设计 1.1 目录 1)目录 2)FPGA简介 3)Verilog HDL简介 4)Verilog HDL UART发送设计 5)结语 1.2 FPGA简介 ...

  6. 基于FPGA的UART异步串行通信发送模块设计与实现

    欢迎关注微信公众号"FPGA科技室",更多内容请关注 下一篇文请点击下列链接(接收模块设计) [基于FPGA的UART异步串行通信接收模块设计与实现] 本文发送模块: 在电子系统中 ...

  7. UART 异步串行通信发送模块设计与实现

    UART 异步串行通信发送模块设计与实现 串口发送模块接口设计 注意:在每一次设计端口时,我们都要求可以随时控制该模块开始和结束,因此在设计每一个模块时,务必要加模块的使能端口(EN)和模块结束端口( ...

  8. (27)System Verilog设计UART接收

    (27)System Verilog设计UART接收 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog设计UART接收 1.UART接收 ...

  9. (28)System Verilog设计UART发送

    (28)System Verilog设计UART发送 1.1 目录 1)目录 2)FPGA简介 3)System Verilog简介 4)System Verilog设计UART发送 1.UART发送 ...

最新文章

  1. 优化C代码常用的几招
  2. 神经网络通过研究任意单个星系,揭示整个宇宙的组成
  3. LVM逻辑卷轴管理和磁盘配额实验
  4. 数据量高并发的数据库优化
  5. tomcat jvm调优
  6. Python基础教程:函数的定义
  7. mysql例题_mysql练习题1
  8. 洛谷 - P3356 火星探险问题(最大费用最大流+拆点+路径打印)
  9. linux下载b站的视频+ffmpeg抽取出mp3
  10. trie树查找前缀串_Trie数据结构(前缀树)
  11. 突破信息封锁,快速建立镜像网站
  12. python基础--函数作用域
  13. Qt qss问题总结
  14. miui8.2 是android 7.0,因与MIUI 8.2撞车 小米5暂缺失安卓7.0
  15. 用户故事与敏捷方法—迭代计划
  16. 好看的php表格样式,3款精美的css3 table表格样式设计
  17. iOS 加速计 摇一摇
  18. Re.常系数齐次递推
  19. [SHOI2015]激光发生器
  20. 阿里王坚:每一个物体都将是互联网终端

热门文章

  1. 网线传输速度测试_网线测试参数说明
  2. 超参数优化专题之工具—microsoft/nni(1)
  3. 数字化转型走基层:东呈国际集团重新定义中国酒店行业发展
  4. 看过来,2022最后一期大咖说-大厂可观测来啦~
  5. 成功解决:Failed to load resource: net::ERR_FILE_NOT_FOUND
  6. Linux基本命令学习 《二》
  7. 关于IOS购买商品回调至JAVA后端
  8. 电脑批量webp压缩大小?手把手教你webp压缩
  9. 金山词霸在IE调用的PDF文件取词问题(摘自sothic)
  10. 基于微信小程序的生活日用品交易平台 的设计与实现