当前位置: 首页 > news >正文

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-11 UART串口接收驱动设计

软件版本:VIVADO2021.1

操作系统:WIN10 64bit

硬件平台:适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA

实验平台:米联客-MLK-H3-CZ08-7100开发板

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

目录

1概述

2 UART接收驱动设计

2.1系统框图

2.2UART接收时序

2.3驱动接口时序图

2.4驱动源码

3 FPGA工程

4 仿真测试

4.1添加仿真测试源码

4.3开始仿真


1概述

UART串口通信是应用非常广泛的一种串行异步通信方式,常用的异步串口包括RS232\RS482\RS485。

RS232的逻辑1的电平为-3~-15V,逻辑0的电平为+3~+15V,下图是老式的DB9串口线。

标准的DB9接口定义如下:

序号

DB9公头

DB9母头

1

CD

载波检测

CD

载波检测

2

RXD

接收端接收

TXD

发送端发送数据

3

TXD

发送数据

RXD

接收端接收数据

4

DTR

数据终端就绪

DTR

数据终端就绪

5

GND

系统接地

GND

系统接地

6

DSR

数据准备就绪

DSR

数据准备就绪

7

RTS

发送请求

CTS

清除请求

8

CTS

清除发送

RTS

发送请求

9

RI

振铃指示器

RI

振铃指示器

实际上一般RS232只使用到TXD RXD两个信号。

RS485/422采用差分信号负逻辑,逻辑“1”以两线间的电压差为-(2~6)V表示;逻辑“0”以两线间的电压差为+(2~6)V表示,由于采用差分方式可以具有更高的速度和更强的抗干扰能力,具有更远的传输距离。由于RS485/RS422更多出现在工业场合,因此一般采用接线端子方式接线。

老式DB9串口基本上已经消失了,但是UART串口更加广泛地使用,比如我们常见的USB串口,就是通过USB接口芯片,实现了以TTL电平方式的UART串口通信。数据通过USB接口进行传输,通过UART串口芯片完成USB协议到UART串口协议的相互转换。

实验目的:

1:实现UART串口接收控制器的设计

2:完成仿真验证,仿真模拟发送三组数据接收成功

2 UART接收驱动设计

2.1系统框图

如下图所示,米联客设计的UART发送控制器包含4个主要模块:波特率发生器、抗干扰过采样模块、起始位检测模块,移位模块。

2.2UART接收时序

下图中,UART串口通信数据格式包括1bit起始位、8bits数据位、1bit停止位,不包含奇偶校验位。

上图中,对接收数据进行过采样,对一个波特率位的数据以8倍波特率采样,通过判断低电平和高电平采样的次数,决定最终采集的是高电平还是低电平。多次采样可以提高总线的抗干扰能力。

在开始编写串口接收驱动前,我们需要了解以下概念:

波特率UART采用异步通信方式,数据收发双方只有在同一波特率才能正常通信。波特率代表了UART完成1个时间单位数据位或者控制位的时间。通常,我们需要对系统时钟进行分频来产生正确的波特率,所以计算分频系数尤为重要,比如系统时钟是100_000_000HZ,波特率是115200,那么分频系数为=100_000_000/115200-1

起始位UART数据总线由高电平变低电平,并且持续1个波特率时间代表数据的起始。

数据位每个数据位占用1个波特率时间,本文实验发送1BYTE字节需要占用8个波特率时间。

停止位如果没有奇偶校验位,数据位结束后,保持1/1.5/2个波特率的高电平代表了停止位。

奇偶校验用于校对数据,对于UART通信,可以根据实际情况选择是否需要支持奇偶校验。

2.3驱动接口时序图

米联客设计了一种通用简洁的驱动接口,包含以下信号:

xxx_rdata:接收的数据

xxx_rvalid:接收的有效数据

这里xxx代表了uart

2.4驱动源码

代码如下:

/*******************************UART接收驱动*********************
--以下是米联客设计的UART接收驱动器
--1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨
--2.uart_rvalid_o有效,代表数据uart_rdata_o有效
--3.抗干扰设计,对每个bit采用8倍采样,如果采样到低电平的次数大于高电平,则为0,否则为1
*********************************************************************/`timescale 1ns / 1ns//仿真时间刻度/精度module uiuart_rx#
(parameter integer  BAUD_DIV     = 10416  //波特率分频参数,BAUD_DIV=系统时钟频率/波特率-1 比如100M系统时钟,波特率115200 BAUD_DIV= 100_000_000/115200-1
)
(
input I_clk, //系统时钟输入
input I_uart_rstn,//系统复位输入
input I_uart_rx,//uart rx 总线信号输入
output [7:0] O_uart_rdata,//uart rx接收到的数据输出
output O_uart_rvalid// uart rx 接收数据有效信号,当为1的时候O_uart_rdata数据有效
);localparam  BAUD_DIV_SAMP = (BAUD_DIV/8)-1;                            //多次采样,按照波特率系数的八分之一进行采样wire bps_en       ; //波特率使能信号
wire samp_en      ; //采样使能信号
wire bit_cap_done ; //uart rx总线信号采样有效数据完成
wire uart_rx_done ; //uart 1byte 接收完成
wire bit_data     ; //接收的1bit数据
wire I_uart_rxnt  ; //I_uart_rxnt的启动信号检测,当变为低电平,代表可能存在起始位(UART 起始位为低电平)reg [13:0]  baud_div = 14'd0;//波特率分频计数器
reg [13:0]  samp_cnt = 14'd0;//采样计数器
reg [4 :0]  I_uart_rx_r = 5'd0;//异步采集多次寄存
reg [3 :0]  bit_cnt=4'd0;//bit 计数器
reg [3 :0]  cap_cnt=4'd0;//cap 计数器
reg [4 :0]  rx_bit_tmp = 5'd0;//rx_bit_tmp用于多次采样,通过计算采样到高电平次数和低电平次数,判断本次采样是高电平还是低电平
reg [7 :0]  rx_data = 8'd0;//数据接收寄存器reg bps_start_en_r = 1'b0;
reg bit_cap_done_r = 1'b0;
reg bps_start_en,start_check_done,start_check_failed;assign bps_en       =   (baud_div == (BAUD_DIV - 1'b1));                     //完成一次波特率传输信号
assign samp_en      =   (samp_cnt == (BAUD_DIV_SAMP - 1'b1 ));               //完成一次波特率采样信号
assign bit_cap_done =   (cap_cnt  == 3'd7);//采样计数
assign uart_rx_done =   (bit_cnt  == 9)&&(baud_div == BAUD_DIV >> 1);//当停止位开始,提前半停止位,发送uart_rx_done信号,以便提前准备进入下一个数据的接收assign bit_data     =   (rx_bit_tmp < 5'd15) ? 0 : 1; //rx_bit_tmp用于多次采样,通过计算采样到高电平次数和低电平次数,判断本次采样是高电平还是低电平,提高抗干扰能力
//连续5次信号拉低,判断开始传输
assign I_uart_rxnt  =   I_uart_rx_r[4] | I_uart_rx_r[3] | I_uart_rx_r[2] | I_uart_rx_r[1] | I_uart_rx_r[0];
assign O_uart_rdata   =   rx_data;
assign O_uart_rvalid  =   uart_rx_done;   //波特率计数器
always@(posedge I_clk)beginif(bps_start_en && baud_div < BAUD_DIV)                 //baud_div计数,目标值BAUD_DIV baud_div <= baud_div + 1'b1;else baud_div <= 14'd0;
end//8bit采样使能,8倍波特率采样,也就是这个计数器,用于产生8倍过采样
always@(posedge I_clk)beginif(bps_start_en && samp_cnt < BAUD_DIV_SAMP)             //bps_start_en高电平有效,开始对bit进行采样,samp_cnt以8倍于波特率速度对每个bit采样samp_cnt <= samp_cnt + 1'b1;                         //samp_cnt计数+1       else samp_cnt <= 14'd0;                                   //samp_cnt计数清零
end//uart rx bus asynchronous to Synchronous
always@(posedge I_clk)begin I_uart_rx_r <= {I_uart_rx_r[3:0],I_uart_rx};             //I_uart_rx的数据存入I_uart_rx_r进行缓存
end//uart接收启动检查
always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || uart_rx_done || start_check_failed) //bps_start_en拉低的三种情况,复位、接收完成、校验失败bps_start_en    <= 1'b0;                                               //接收结束else if((I_uart_rxnt == 1'b0)&(bps_start_en==1'b0))//当判断到I_uart_rxnt == 1'b0,并且总线之前空闲(bps_start_en==1'b0,代表总线空闲)bps_start_en    <= 1'b1;//使能波特率计数器使能
end//uart接收启动使能
always@(posedge I_clk)beginbps_start_en_r    <= bps_start_en;                              //bps_start_en信号打一拍,方便后续上升沿捕捉
endalways@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || start_check_failed)begin//当系统复位,或者start_check_failed,重置start_check_done和start_check_failedstart_check_done    <= 1'b0;start_check_failed  <= 1'b0;end    else if(bps_start_en == 1'b1&&bps_start_en_r == 1'b0) begin//当检测到start信号,也重置start_check_done和start_check_failedstart_check_done    <= 1'b0;start_check_failed  <= 1'b0;endelse if((bit_cap_done&&bit_cap_done_r==1'b0)&&(start_check_done == 1'b0))begin//第一个波特率采样,用于判断是否一个有效的起始位,如果不是有效的,start_check_failed设置为1start_check_failed <= bit_data ? 1'b1 : 1'b0;start_check_done   <= 1'b1;//不管是否start_check_failed==1,都会设置start_check_done=1,但是start_check_failed==1,会下一个系统时钟重置start_check_done=0end     
end//bits 计数器
always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || uart_rx_done || bps_start_en == 1'b0)//复位、接收完成、或者总线空闲(bps_start_en == 1'b0),重置bit_cntbit_cnt   <= 4'd0;                                                    else if(bps_en)//每一个bps_en有效,加1bit_cnt <= bit_cnt + 1'b1;  // bit_cnt计数器用于计算当前采样了第几个bit 
end//8次过采样,提高抗干扰
always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || bps_en == 1'b1 || bps_start_en == 1'b0) begin //当I_uart_rstn=0或者bps_en=1或者bps_start_en==0,重置cap_cnt和rx_bit_tmpcap_cnt     <= 4'd0;rx_bit_tmp  <= 5'd15; endelse if(samp_en)begin//bit采样使能cap_cnt     <= cap_cnt + 1'b1;//cap_cnt用于记录了当前是第几次过采样,1个bit采样8次rx_bit_tmp  <= I_uart_rx_r[4] ? rx_bit_tmp + 1'b1 :  rx_bit_tmp - 1'b1;   //多次采样,如果是高电平+1,如果是低电平-1,最终看本次bit采样结束rx_bit_tmp如果小于15代表是低电平end                                                                                   
end//寄存一次bit_cap_done,用于产生高电平触发脉冲下面用到
always@(posedge I_clk)bit_cap_done_r <= bit_cap_done;always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || bps_start_en == 1'b0)//当复位或者总线空闲,重置rx_datarx_data  <= 8'd0;  else if(start_check_done&&(bit_cap_done&&bit_cap_done_r==1'b0)&&bit_cnt < 9)//当start_check_done有效,并且bit_cnt<9,每次bit_cap_done有效,完成一次移位寄存rx_data  <= {bit_data,rx_data[7:1]};                                         //串并转换,将数据存入rx_data 中,共8位
endendmodule

3 FPGA工程

fpga工程的创建过程不再重复,如有不清楚的请看前面实验

米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹

01_rtl:放用户编写的rtl代码

02_sim:仿真文件或者工程

03_ip:放使用到的ip文件

04_pin:放fpga的pin脚约束文件或者时序约束文件

05_boot:放编译好的bit或者bin文件(一般为空)

06_doc:放本一些相关文档(一般为空)

4 仿真测试

4.1添加仿真测试源码

仿真测试文件存放在工程目录uisrc\02_sim中,源码如下:

`timescale 1ns / 1ns//仿真时间刻度/精度module uiuart_rx#(parameter integer  BAUD_DIV     = 10416  //波特率分频参数,BAUD_DIV=系统时钟频率/波特率-1 比如100M系统时钟,波特率115200 BAUD_DIV= 100_000_000/115200-1)(input I_clk, //系统时钟输入input I_uart_rstn,//系统复位输入input I_uart_rx,//uart rx 总线信号输入output [7:0] O_uart_rdata,//uart rx接收到的数据输出output O_uart_rvalid// uart rx 接收数据有效信号,当为1的时候O_uart_rdata数据有效);localparam  BAUD_DIV_SAMP = (BAUD_DIV/8)-1;          //多次采样,按照波特率系数的八分之一进行采样wire bps_en       ; //波特率使能信号wire samp_en      ; //采样使能信号wire bit_cap_done ; //uart rx总线信号采样有效数据完成wire uart_rx_done ; //uart 1byte 接收完成wire bit_data     ; //接收的1bit数据wire I_uart_rxnt  ; //I_uart_rxnt的启动信号检测,当变为低电平,代表可能存在起始位(UART 起始位为低电平)reg [13:0]  baud_div = 14'd0;//波特率分频计数器reg [13:0]  samp_cnt = 14'd0;//采样计数器reg [4 :0]  I_uart_rx_r = 5'd0;//异步采集多次寄存reg [3 :0]  bit_cnt=4'd0;//bit 计数器reg [3 :0]  cap_cnt=4'd0;//cap 计数器reg [4 :0]  rx_bit_tmp = 5'd0;//rx_bit_tmp用于多次采样,通过计算采样到高电平次数和低电平次数,判断本次采样是高电平还是低电平reg [7 :0]  rx_data = 8'd0;//数据接收寄存器reg bps_start_en_r = 1'b0;reg bit_cap_done_r = 1'b0;reg bps_start_en,start_check_done,start_check_failed;assign bps_en       =   (baud_div == (BAUD_DIV - 1'b1));                     //完成一次波特率传输信号assign samp_en      =   (samp_cnt == (BAUD_DIV_SAMP - 1'b1 ));               //完成一次波特率采样信号assign bit_cap_done =   (cap_cnt  == 3'd7);//采样计数assign uart_rx_done =   (bit_cnt  == 9)&&(baud_div == BAUD_DIV >> 1);//当停止位开始,提前半停止位,发送uart_rx_done信号,以便提前准备进入下一个数据的接收assign bit_data     =   (rx_bit_tmp < 5'd15) ? 0 : 1; //rx_bit_tmp用于多次采样,通过计算采样到高电平次数和低电平次数,判断本次采样是高电平还是低电平,提高抗干扰能力//连续5次信号拉低,判断开始传输assign I_uart_rxnt  =   I_uart_rx_r[4] | I_uart_rx_r[3] | I_uart_rx_r[2] | I_uart_rx_r[1] | I_uart_rx_r[0];assign O_uart_rdata   =   rx_data;assign O_uart_rvalid  =   uart_rx_done;  //波特率计数器always@(posedge I_clk)beginif(bps_start_en && baud_div < BAUD_DIV)                 //baud_div计数,目标值BAUD_DIVbaud_div <= baud_div + 1'b1;else baud_div <= 14'd0;end//8bit采样使能,8倍波特率采样,也就是这个计数器,用于产生8倍过采样always@(posedge I_clk)beginif(bps_start_en && samp_cnt < BAUD_DIV_SAMP)             //bps_start_en高电平有效,开始对bit进行采样,samp_cnt以8倍于波特率速度对每个bit采样samp_cnt <= samp_cnt + 1'b1;                         //samp_cnt计数+1      else samp_cnt <= 14'd0;                                   //samp_cnt计数清零end//uart rx bus asynchronous to Synchronousalways@(posedge I_clk)begin I_uart_rx_r <= {I_uart_rx_r[3:0],I_uart_rx};             //I_uart_rx的数据存入I_uart_rx_r进行缓存end//uart接收启动检查always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || uart_rx_done || start_check_failed) //bps_start_en拉低的三种情况,复位、接收完成、校验失败bps_start_en    <= 1'b0;                                               //接收结束else if((I_uart_rxnt == 1'b0)&(bps_start_en==1'b0))//当判断到I_uart_rxnt == 1'b0,并且总线之前空闲(bps_start_en==1'b0,代表总线空闲)bps_start_en    <= 1'b1;//使能波特率计数器使能end//uart接收启动使能always@(posedge I_clk)beginbps_start_en_r    <= bps_start_en;               //bps_start_en信号打一拍,方便后续上升沿捕捉endalways@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || start_check_failed)begin//当系统复位,或者start_check_failed,重置start_check_done和start_check_failedstart_check_done    <= 1'b0;start_check_failed  <= 1'b0;end    else if(bps_start_en == 1'b1&&bps_start_en_r == 1'b0) begin//当检测到start信号,也重置start_check_done和start_check_failedstart_check_done    <= 1'b0;start_check_failed  <= 1'b0;endelse if((bit_cap_done&&bit_cap_done_r==1'b0)&&(start_check_done == 1'b0))begin//第一个波特率采样,用于判断是否一个有效的起始位,如果不是有效的,start_check_failed设置为1start_check_failed <= bit_data ? 1'b1 : 1'b0;start_check_done   <= 1'b1;//不管是否start_check_failed==1,都会设置start_check_done=1,但是start_check_failed==1,会下一个系统时钟重置start_check_done=0end    end//bits 计数器always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || uart_rx_done || bps_start_en == 1'b0)//复位、接收完成、或者总线空闲(bps_start_en == 1'b0),重置bit_cntbit_cnt   <= 4'd0;                                                    else if(bps_en)//每一个bps_en有效,加1bit_cnt <= bit_cnt + 1'b1;  // bit_cnt计数器用于计算当前采样了第几个bitend//8次过采样,提高抗干扰always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || bps_en == 1'b1 || bps_start_en == 1'b0) begin //当I_uart_rstn=0或者bps_en=1或者bps_start_en==0,重置cap_cnt和rx_bit_tmpcap_cnt     <= 4'd0;rx_bit_tmp  <= 5'd15;endelse if(samp_en)begin//bit采样使能cap_cnt     <= cap_cnt + 1'b1;//cap_cnt用于记录了当前是第几次过采样,1个bit采样8次rx_bit_tmp  <= I_uart_rx_r[4] ? rx_bit_tmp + 1'b1 :  rx_bit_tmp - 1'b1;   //多次采样,如果是高电平+1,如果是低电平-1,最终看本次bit采样结束rx_bit_tmp如果小于15代表是低电平end                                                                                  end//寄存一次bit_cap_done,用于产生高电平触发脉冲下面用到always@(posedge I_clk)bit_cap_done_r <= bit_cap_done;always@(posedge I_clk)beginif(I_uart_rstn == 1'b0 || bps_start_en == 1'b0)//当复位或者总线空闲,重置rx_datarx_data  <= 8'd0;  else if(start_check_done&&(bit_cap_done&&bit_cap_done_r==1'b0)&&bit_cnt < 9)//当start_check_done有效,并且bit_cnt<9,每次bit_cap_done有效,完成一次移位寄存rx_data  <= {bit_data,rx_data[7:1]};                                         //串并转换,将数据存入rx_data 中,共8位endendmodule

4.3开始仿真

选择我们主程序信号

添加进观察窗

删除多余的信号

点击run按键,开始仿真

观察发送程序的仿真结果准确无误

本实验只完成仿真演示,在下一个实验中完成uart收发环路实验。


http://www.mrgr.cn/news/14055.html

相关文章:

  • 【FPGA】HDMI参数信息汇总
  • 宠物空气净化器哪款更值得推荐?希喂和352哪款更好?
  • 35岁零基础能转型AI大模型吗?
  • CSS 终于在 2024 年增加了垂直居中功能
  • Qt调用外部exe并嵌入到Qt界面中(验证成功的成功)
  • 如何解决:Failed to start jenkins.service: Unit not found.
  • P1009 【深基4,例7】阶乘之和
  • Java对象属性比较工具类(可用)
  • 【中秋特惠】南卡Runner Pro5:送给家人的科技健康礼!
  • 不用async与await将异步函数改为同步函数
  • 【递归回溯之floodfill算法专题练习】
  • 了解CSS中的BFC
  • 华为设备默认密码
  • Lombok组件的使用
  • E29.【C语言】练习:sizeof和strlen的习题集(A)
  • matlab 将数组从左向右翻转
  • 电子电气架构 --- 车载网简史(上)
  • 迷雾大陆辅助:VMOS云手机助力升级装备系统秘籍!
  • Python——xml.etree.ElementTree
  • SQL 注入之 sqlmap 实战