UART 通信 协议 (二)
文章目录
目录
前言
一、接收时序图
二、模块设计
1.总体方案
2.接受数据信号同步化
3.边沿检测设计
4.生成采样时钟
5.采样数据求和判决
三、编程实现
四、仿真验证
五、板级调试验证
参考说明
前言
上一篇博客介绍了UART通信协议的内容以及UART 发送的实现。本文接着上篇博客:UART 通信 协议 (一),主要介绍UART 接收的FPGA实现。
设计平台:Vivado IDE 2018.3
硬件平台:武汉芯路恒科技ACX720开发板
(建议PC端查看)
一、接收时序图
由上图,对于接收到的电平信号,我们一般选择在中间时刻进行采样(上升沿采样)。因为中间时刻的电平相对稳定,对应的误码几率也很小,当然还是会存在误码情况的。实际应用中,为了应对强电磁干扰。会对同一个电平信号的不同时间段多次采样,然后对采样结果进行判决。最终确定电平值。
本次设计将对同一电平的不同时刻作 21 次采样。对中间的 7 次采样结果作判决,1 的个数多于 0 的个数则判为 1,否则为 0。
二、模块设计
1.总体方案
输入输出说明:
信号 | 位宽 | 方向 | 功能 |
I_CLK | 1 | I | 时钟信号 |
I_Rst_n | 1 | I | 模块复位信号(低电平有效) |
I_UART_RX | 1 | I | 接受的UART 信号 |
I_BAUD_SELECT | 3 | I | 波特率选择 |
O_DATA | 8 | O | 输出的并行数据 |
O_FINISH | 1 | O | 完成一次传输则有效(置1) |
2.接受数据信号同步化
串口接收的UART信号是一个异步信号,和FPGA内部的逻辑不在同一个时钟域。如果不做跨时钟域处理,很容易出现亚稳态,影响数据接收。
这里用一种较为简单且常用的二级同步器来实现对数据信号 的同步化处理。
一些高速的设计中为了提高平均故障时间,会采取三级同步器。
3.边沿检测设计
在没有数据接收时I_UART_RX保持高电平,一旦出现数据信号,起始信号拉低,那么此时会出现一个下降沿。下降沿的出现就要开始检测数据了,因此检测是否出现下降沿是能够正确接收数据的前提。
下降沿检测属于边沿检测的范畴。主要是利用信号的一级寄存、二级寄存的某种逻辑运算进行边沿检测。
下降沿检测的时序图:
4.生成采样时钟
系统的时钟频率为50MHz。不同波特率对应的采样时钟计数值为:
波特率 | 计数值 |
300 | 7936-1 |
1200 | 1984-1 |
2400 | 992-1 |
9600 | 248-1 |
19200 | 124-1 |
38400 | 62-1 |
57600 | 41-1 |
115200 | 21-1 |
5.采样数据求和判决
通过对每个BIT信号的七个采样点求和,进行判决,最终确定电平值。如果结果大于等于4,那么判为1,小于等于三则判为0。由于结果大于等于4的最高位为1,小于等于3的最高位为0,所以可以直接将求和结果的最高位输出为判决结果。
三、编程实现
总体的模块编程:
module UART_RX (//--------------------输入端口列表-----------------------//input I_CLK,
input I_Rst_n,
input I_UART_RX,
input [2:0] I_BAUD_SELECT,//--------------------输出端口列表-----------------------//output reg [7:0] O_DATA,
output reg O_FINISH );//------------------内部参数、变量定义-------------------//
//波特率 采样时钟 相关参数
localparam BAUD_300_SAMPLE = 13'd7936-1;
localparam BAUD_1200_SAMPLE = 13'd1984-1;
localparam BAUD_2400_SAMPLE = 13'd992-1;
localparam BAUD_9600_SAMPLE = 13'd248-1;
localparam BAUD_19200_SAMPLE = 13'd124-1;
localparam BAUD_38400_SAMPLE = 13'd62-1;
localparam BAUD_57600_SAMPLE = 13'd41-1;
localparam BAUD_115200_SAMPLE = 13'd21-1;//模块状态信号
reg R_STATE;// 模块状态 , 1表示处于busy,0表示处于idle//二级寄存器 同步输入信号
reg R1_UART_RX;
reg R2_UART_RX;//下降沿检测
reg R_1_NEGEDGE_DETECT;
reg R_2_NEGEDGE_DETECT;
wire W_NEGEDGE_RES;//波特率采样时钟 计数相关
reg [12:0] R_BAUD_SAMPLE_COUNT_MAX;
reg [12:0] R_BAUD_SAMPLE_COUNT;
reg [7:0] R_SAMPLE_CLK_COUNT;//采样时钟 产生
reg R_SAMPLE_CLK;//中间7位采样数据 求和 结果存放
reg [2:0] R_SUM_START;
reg [2:0] R_SUM_BIT0;
reg [2:0] R_SUM_BIT1;
reg [2:0] R_SUM_BIT2;
reg [2:0] R_SUM_BIT3;
reg [2:0] R_SUM_BIT4;
reg [2:0] R_SUM_BIT5;
reg [2:0] R_SUM_BIT6;
reg [2:0] R_SUM_BIT7;
reg [2:0] R_SUM_END;//--------------------模块的程序设计---------------------//
//*** 接收数据数据同步 跨时钟域处理
always @ (posedge I_CLK)beginif(!I_Rst_n)beginR1_UART_RX <= 0;R2_UART_RX <= 0;endelse beginR1_UART_RX <= I_UART_RX;R2_UART_RX <= R1_UART_RX;end end//*** 下降沿检测
always @ (posedge I_CLK)beginif(!I_Rst_n)beginR_1_NEGEDGE_DETECT <= 0;R_2_NEGEDGE_DETECT <= 0;endelse beginR_1_NEGEDGE_DETECT <= R2_UART_RX;R_2_NEGEDGE_DETECT <= R_1_NEGEDGE_DETECT;end endassign W_NEGEDGE_RES = (!R_1_NEGEDGE_DETECT) & (R_2_NEGEDGE_DETECT);//*** 生成采样时钟
always @ (posedge I_CLK)beginif(!I_Rst_n)beginR_BAUD_SAMPLE_COUNT_MAX <= 0;endelse begincase (I_BAUD_SELECT) 0:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_300_SAMPLE;end1:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_1200_SAMPLE;end2:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_2400_SAMPLE;end3:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_9600_SAMPLE;end4:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_19200_SAMPLE;end5:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_38400_SAMPLE;end6:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_57600_SAMPLE;end7:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_115200_SAMPLE;end default:beginR_BAUD_SAMPLE_COUNT_MAX <= BAUD_9600_SAMPLE;endendcase end endalways @ (posedge I_CLK)beginif(!I_Rst_n)beginR_BAUD_SAMPLE_COUNT <= 0;endelse if(R_STATE)beginif (R_BAUD_SAMPLE_COUNT == R_BAUD_SAMPLE_COUNT_MAX) beginR_BAUD_SAMPLE_COUNT <= 0;endelse beginR_BAUD_SAMPLE_COUNT <= R_BAUD_SAMPLE_COUNT + 1;end endelse beginR_BAUD_SAMPLE_COUNT <= 0;end end
// 采样时钟 脉宽为一个时钟周期的窄脉冲信号
always @ (posedge I_CLK)beginif(!I_Rst_n)beginR_SAMPLE_CLK <= 0;endelse if(R_BAUD_SAMPLE_COUNT == 13'd2)beginR_SAMPLE_CLK <= 1;endelse beginR_SAMPLE_CLK <= 0;end end//*** 采样时钟 计数
always @ (negedge I_CLK)//下降沿beginif(!I_Rst_n)beginR_SAMPLE_CLK_COUNT <= 0;endelse if((R_SAMPLE_CLK_COUNT == 8'd209) || (R_SAMPLE_CLK_COUNT == 8'd15 && (R_SUM_START >= 3)))beginR_SAMPLE_CLK_COUNT <= 0;endelse if(R_SAMPLE_CLK)beginR_SAMPLE_CLK_COUNT <= R_SAMPLE_CLK_COUNT + 1;endelse beginR_SAMPLE_CLK_COUNT <= R_SAMPLE_CLK_COUNT;end end//*** 采样数据求和
always @ (negedge I_CLK)//下降沿beginif(!I_Rst_n)beginR_SUM_START <=3'd0;R_SUM_BIT0 <=3'd0;R_SUM_BIT1 <=3'd0;R_SUM_BIT2 <=3'd0;R_SUM_BIT3 <=3'd0;R_SUM_BIT4 <=3'd0;R_SUM_BIT5 <=3'd0;R_SUM_BIT6 <=3'd0;R_SUM_BIT7 <=3'd0;R_SUM_END <=3'd0;endelse if(R_SAMPLE_CLK)begincase (R_SAMPLE_CLK_COUNT) 0:beginR_SUM_START <=3'd0;R_SUM_BIT0 <=3'd0;R_SUM_BIT1 <=3'd0;R_SUM_BIT2 <=3'd0;R_SUM_BIT3 <=3'd0;R_SUM_BIT4 <=3'd0;R_SUM_BIT5 <=3'd0;R_SUM_BIT6 <=3'd0;R_SUM_BIT7 <=3'd0;R_SUM_END <=3'd0;end8,9,10,11,12,13,14:beginR_SUM_START <= R_SUM_START + R2_UART_RX;end29,30,31,32,33,34,35:beginR_SUM_BIT0 <= R_SUM_BIT0 + R2_UART_RX;end50,51,52,53,54,55,56:beginR_SUM_BIT1 <= R_SUM_BIT1 + R2_UART_RX;end71,72,73,74,75,76,77:beginR_SUM_BIT2 <= R_SUM_BIT2 + R2_UART_RX;end92,93,94,95,96,97,98:beginR_SUM_BIT3 <= R_SUM_BIT3 + R2_UART_RX;end113,114,115,116,117,118,119:beginR_SUM_BIT4 <= R_SUM_BIT4 + R2_UART_RX;end134,135,136,137,138,139,140:beginR_SUM_BIT5 <= R_SUM_BIT5 + R2_UART_RX;end 155,156,157,158,159,160,161:beginR_SUM_BIT6 <= R_SUM_BIT6 + R2_UART_RX;end176,177,178,179,180,181,182:beginR_SUM_BIT7 <= R_SUM_BIT7 + R2_UART_RX;end197,198,199,200,201,202,203:beginR_SUM_END <= R_SUM_END + R2_UART_RX;end default:beginR_SUM_START <= R_SUM_START;R_SUM_BIT0 <= R_SUM_BIT0 ;R_SUM_BIT1 <= R_SUM_BIT1 ;R_SUM_BIT2 <= R_SUM_BIT2 ;R_SUM_BIT3 <= R_SUM_BIT3 ;R_SUM_BIT4 <= R_SUM_BIT4 ;R_SUM_BIT5 <= R_SUM_BIT5 ;R_SUM_BIT6 <= R_SUM_BIT6 ;R_SUM_BIT7 <= R_SUM_BIT7 ;R_SUM_END <= R_SUM_END ;endendcase end end//判决
always @ (posedge I_CLK)beginif(!I_Rst_n)beginO_DATA <= 0;endelse if(R_SAMPLE_CLK_COUNT == 8'd209)beginO_DATA[0] <= R_SUM_BIT0[2];O_DATA[1] <= R_SUM_BIT1[2];O_DATA[2] <= R_SUM_BIT2[2];O_DATA[3] <= R_SUM_BIT3[2];O_DATA[4] <= R_SUM_BIT4[2];O_DATA[5] <= R_SUM_BIT5[2];O_DATA[6] <= R_SUM_BIT6[2];O_DATA[7] <= R_SUM_BIT7[2];end end//*** 传输完成信号
always @ (posedge I_CLK)beginif(!I_Rst_n)beginO_FINISH <= 0;endelse if(R_SAMPLE_CLK_COUNT == 8'd209)beginO_FINISH <= 1;endelse beginO_FINISH <= 0;end end//*** 模块状态信号
always @ (posedge I_CLK)beginif(!I_Rst_n)beginR_STATE <= 0;endelse if(W_NEGEDGE_RES)beginR_STATE <= 1;endelse if(O_FINISH || (R_SAMPLE_CLK_COUNT == 8'd15 && (R_SUM_START >= 3)) || (R_SAMPLE_CLK_COUNT == 8'd204 && (R_SUM_END <= 3)))beginR_STATE <= 0;endelse beginR_STATE <= R_STATE;endendendmodule
四、仿真验证
利用了上一篇博客,UART发送模块与UART接收模块进行对接。编写testbench:
`timescale 1ns/1ps
module TB_UART_RX ();//-----------------被测试模块输入接口声明--------------------//
// TX
reg I_CLK;
reg I_Rst_n;
reg I_VALID;
reg [7:0] I_DATA;
// RX
wire I_UART_RX; //----------------被测试模块的输出接口声明-------------------//
// RX
wire [7:0] O_DATA;
wire O_FINISH_RX;
// TX
wire O_STATE;
wire O_FINISH_TX; //-----------------------测试程序---------------------------//
//产生激励时钟
`define CLK_PERIOD 20
initial I_CLK = 0 ;
always #(`CLK_PERIOD/2) I_CLK = ~ I_CLK;//初始化控制信号initialbeginI_Rst_n = 0;I_DATA = 8'b0;I_VALID = 0;// I_BAUD_SELECT = 3'd3;#(`CLK_PERIOD * 10 +2);I_Rst_n = 1;#(`CLK_PERIOD * 10);//发送数据 1I_DATA = 8'b0110_1001;I_VALID = 1;#(`CLK_PERIOD * 1);I_VALID = 0;@(posedge O_FINISH_TX);#(`CLK_PERIOD * 1000);//发送数据 2I_DATA = 8'b1110_1011;I_VALID = 1;#(`CLK_PERIOD * 1);I_VALID = 0;@(posedge O_FINISH_TX);#(`CLK_PERIOD * 50);$stop; end//被测试模块例化 TX
UART_TX inst_UART_TX(.I_CLK (I_CLK),.I_Rst_n (I_Rst_n),.I_VALID (I_VALID),.I_DATA (I_DATA),.I_BAUD_SELECT (3'd3),.O_STATE (O_STATE),.O_DATA (I_UART_RX),.O_FINISH (O_FINISH_TX));//被测试模块例化 RX
UART_RX inst_UART_RX(.I_CLK (I_CLK),.I_Rst_n (I_Rst_n),.I_UART_RX (I_UART_RX),.I_BAUD_SELECT (3'd3),.O_DATA (O_DATA),.O_FINISH (O_FINISH_RX));endmodule
仿真波形:
五、板级调试验证
验证思路:利用VIO IP核进行数据接收。配置如下:
编写顶层模块:
module TOP_UART_RX_TEST (//--------------------输入端口列表-----------------------//input I_CLK,
input I_Rst_n,
input I_UART_RX);//------------------内部参数、变量定义-------------------//wire [7:0] O_DATA;
wire O_FINISH;reg [7:0] R_O_DATA;//--------------------模块的程序设计---------------------//UART_RX inst_UART_RX(.I_CLK (I_CLK),.I_Rst_n (I_Rst_n),.I_UART_RX (I_UART_RX),.I_BAUD_SELECT (3'd3),.O_DATA (O_DATA),.O_FINISH (O_FINISH));always @ (posedge I_CLK)beginif(!I_Rst_n)beginR_O_DATA <= 0;endelse if(O_FINISH)beginR_O_DATA <= O_DATA;end else beginR_O_DATA <= R_O_DATA;endendUART_VIO_RX your_instance_name (.clk(I_CLK), // input wire clk.probe_in0(R_O_DATA) // input wire [7 : 0] probe_in0
);endmodule
然后对设计进行综合、布局布线、约束、实现,下载比特流文件。结合串口助手进行相关调试。
参考说明
[1].小梅哥 Xilinx FPGA 自学教程 v2.0
UART 通信 协议 (二)相关推荐
- FPGA基础知识极简教程(6)UART通信与移位寄存器的应用
博文目录 写在前面 正文 关于UART的介绍 UART通信过程 UART.RS232以及TTL之间的关系 UART的使用场合 有关UART的总结 调试UART的技巧 UART的Verilog实现 波特 ...
- UART总线协议——esp32学习笔记
目录 UART理论部分 一.UART简介 二.通信基础 (一)并行和串行 (二)单工和双工 (三)波特率 三.UART帧格式 四.UART硬件连接 五.UART控制器 Exynos4412下的UART ...
- Android10.0 Binder通信原理(二)-Binder入门篇
摘要:本节主要来讲解Android10.0 Binder的设计原理,如何设计一个Binder通信 阅读本文大约需要花费15分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分 ...
- MSP430F5529 DriverLib 库函数学习笔记(四)UART通信
目录 硬知识 USCI通信模块 USCI的UART模式 1. USCI初始化和复位 2. 异步通信字符格式 3. 异步多机通信模式 4. 自动波特率检测 5. IrDA编码和解码 6. 自动错误检测 ...
- FPGA UART总线协议简介
1.1 FPGA UART总线协议简介 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA UART总线协议简介: 5)结束语. 1.1.2 本节引言 " ...
- openmv和stm32串口通信完成二维码识别
openmv和stm32串口通信完成二维码识别 文章目录 前言 一.所用的硬件: 二.openmv端 2.stm32端 总结 前言 注:我只是个大一的小白,本文只完成基本功能,希望能帮助有困惑的人(我 ...
- 一文理解UART通信
还记得当年的打印机,鼠标和调制解调器吗?他们都有巨大笨重的连接器和粗电缆,并且必须拧到你的电脑上.这些设备正是使用UART协议与计算机进行通信.虽然USB几乎完全取代了旧的电缆和连接器,但UART绝对 ...
- FPGA实现uart串口协议
reference:正点原子视频教程 具体代码请参考B站正点原子官方 UART串口通信原理 是一种采用异步串行通信方式的通用异步手法传输器. 因为是异步通信所以,使用的时候要进行同步到系统时钟下,不然 ...
- UART总线协议详解
文章目录 1.UART概念 1.1硬件连接 2. RS232总线协议 2.1硬件连接 3. RS485总线协议 3.1硬件连接 1.UART概念 UART(Universal Asynchrono ...
最新文章
- 进程通信学习笔记(System V消息队列)
- 浅谈安卓线程池相关问题
- socket第三方库 AsyncSocket(GCDAsyncSocket)
- 二元运算 FFT+分治
- 分享几个可供学习,休闲的网站
- tiktok+独立站怎么引流?
- JavaBean与Map相互转换
- 【Luogu1363】幻想迷宫
- 帆软填报JS不刷新页面排序表格
- java 设置系统参数_Java 设置系统参数和运行参数
- 实战 Nginx 与 PHP(FastCGI)的安装、配置与优化
- php+log+iis,利用nxlog以syslog方式发送iis日志
- 强大的网页数据库管理工具Adminer
- iPhone所有手机型号屏幕尺寸及H5的CSS适配
- c语言输出26个小写英文字母,c语言题。 按顺序打印输出26个英文字母,
- Qt雪花飘落程序,下雪
- mybatis-plus乐观锁重试机制配置重置次数
- 计算机中现代操作系统两个基本特征是什么,现代操作系统的两个基本特征是资源共享和...
- android 跳转oppo应用中心_Android 遍历手机应用,跳转应用市场详情页面
- Verilog RTL 代码设计——译码器计数器
热门文章
- 得用户者得天下 解析明基的保时捷设计水准
- 美的华为鸿蒙,董明珠万没想到,格力终将被美的超越,华为鸿蒙“功不可没”...
- Qt延时和startTimer
- 闲云野鹤:吃鸡(四)之场景制作—用unity内置草功能制作草
- IDEA提交git代码,配置文件乱码
- android 照片拼接长图_手机照片拼接长图软件|照片拼接长图app下载v2.0-乐游网软件下载...
- 苹果系统下载了python软件怎么卸载_mac怎么卸载pycharm
- 国科大学习资料--多媒体分析与理解(卢汉请)-2019期末考试题
- renderdoc捕获的mesh,通过插件一键导出成fbx
- 操作系统设备管理知识点总结