文章目录

目录

前言

一、接收时序图

二、模块设计

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 通信 协议 (二)相关推荐

  1. FPGA基础知识极简教程(6)UART通信与移位寄存器的应用

    博文目录 写在前面 正文 关于UART的介绍 UART通信过程 UART.RS232以及TTL之间的关系 UART的使用场合 有关UART的总结 调试UART的技巧 UART的Verilog实现 波特 ...

  2. UART总线协议——esp32学习笔记

    目录 UART理论部分 一.UART简介 二.通信基础 (一)并行和串行 (二)单工和双工 (三)波特率 三.UART帧格式 四.UART硬件连接 五.UART控制器 Exynos4412下的UART ...

  3. Android10.0 Binder通信原理(二)-Binder入门篇

    摘要:本节主要来讲解Android10.0 Binder的设计原理,如何设计一个Binder通信 阅读本文大约需要花费15分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分 ...

  4. MSP430F5529 DriverLib 库函数学习笔记(四)UART通信

    目录 硬知识 USCI通信模块 USCI的UART模式 1. USCI初始化和复位 2. 异步通信字符格式 3. 异步多机通信模式 4. 自动波特率检测 5. IrDA编码和解码 6. 自动错误检测 ...

  5. FPGA UART总线协议简介

    1.1 FPGA UART总线协议简介 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA UART总线协议简介: 5)结束语. 1.1.2 本节引言 " ...

  6. openmv和stm32串口通信完成二维码识别

    openmv和stm32串口通信完成二维码识别 文章目录 前言 一.所用的硬件: 二.openmv端 2.stm32端 总结 前言 注:我只是个大一的小白,本文只完成基本功能,希望能帮助有困惑的人(我 ...

  7. 一文理解UART通信

    还记得当年的打印机,鼠标和调制解调器吗?他们都有巨大笨重的连接器和粗电缆,并且必须拧到你的电脑上.这些设备正是使用UART协议与计算机进行通信.虽然USB几乎完全取代了旧的电缆和连接器,但UART绝对 ...

  8. FPGA实现uart串口协议

    reference:正点原子视频教程 具体代码请参考B站正点原子官方 UART串口通信原理 是一种采用异步串行通信方式的通用异步手法传输器. 因为是异步通信所以,使用的时候要进行同步到系统时钟下,不然 ...

  9. UART总线协议详解

    文章目录 1.UART概念 1.1硬件连接 2. RS232总线协议 2.1硬件连接 3. RS485总线协议 3.1硬件连接 1.UART概念   UART(Universal Asynchrono ...

最新文章

  1. 进程通信学习笔记(System V消息队列)
  2. 浅谈安卓线程池相关问题
  3. socket第三方库 AsyncSocket(GCDAsyncSocket)
  4. 二元运算 FFT+分治
  5. 分享几个可供学习,休闲的网站
  6. tiktok+独立站怎么引流?
  7. JavaBean与Map相互转换
  8. 【Luogu1363】幻想迷宫
  9. 帆软填报JS不刷新页面排序表格
  10. java 设置系统参数_Java 设置系统参数和运行参数
  11. 实战 Nginx 与 PHP(FastCGI)的安装、配置与优化
  12. php+log+iis,利用nxlog以syslog方式发送iis日志
  13. 强大的网页数据库管理工具Adminer
  14. iPhone所有手机型号屏幕尺寸及H5的CSS适配
  15. c语言输出26个小写英文字母,c语言题。 按顺序打印输出26个英文字母,
  16. Qt雪花飘落程序,下雪
  17. mybatis-plus乐观锁重试机制配置重置次数
  18. 计算机中现代操作系统两个基本特征是什么,现代操作系统的两个基本特征是资源共享和...
  19. android 跳转oppo应用中心_Android 遍历手机应用,跳转应用市场详情页面
  20. Verilog RTL 代码设计——译码器计数器

热门文章

  1. 得用户者得天下  解析明基的保时捷设计水准
  2. 美的华为鸿蒙,董明珠万没想到,格力终将被美的超越,华为鸿蒙“功不可没”...
  3. Qt延时和startTimer
  4. 闲云野鹤:吃鸡(四)之场景制作—用unity内置草功能制作草
  5. IDEA提交git代码,配置文件乱码
  6. android 照片拼接长图_手机照片拼接长图软件|照片拼接长图app下载v2.0-乐游网软件下载...
  7. 苹果系统下载了python软件怎么卸载_mac怎么卸载pycharm
  8. 国科大学习资料--多媒体分析与理解(卢汉请)-2019期末考试题
  9. renderdoc捕获的mesh,通过插件一键导出成fbx
  10. 操作系统设备管理知识点总结