FPGA三大串行通信接口之UART
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用于主机与辅助设备通信,如汽车音响与外接AP之间的通信,与PC机通信包括与监控调试器和其它器件,如EEPROM通信。
UART 通信在使用前需要做多项设置,最常见的设置包括数据位数、波特率大小、奇偶校验类型和停止位数。
数据位(Data bits): 该参数定义单个 UART 数据传输在开始到停止期间发送的数据位数。 可选择为: 5、 6、 7 或者 8(默认)。
波特率(Baud):是指从一设备发到另一设备的波特率,即每秒钟可以通信的数据比特个数。 典型的波特率有 300, 1200, 2400, 9600, 19200, 115200 等。一般通信两端设备都要设为相同的波特率,但有些设备也可设置为自动检测波特率。
奇偶校验类型(Parity Type):是用来验证数据的正确性。奇偶校验一般不使用,如果使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。在偶校验中,因为奇偶校验位会被相应的置 1 或 0(一般是最高位或最低位),所以数据会被改变以使得所有传送的数位(含字符的各数位和校验位)中“1”的个数为偶数;在奇校验中,所有传送的数位(含字符的各数位和校验位)中“1”的个数为奇数。奇偶校验可以用于接受方检查传输是否发送生错误,如果某一字节中“1”的个数发生了错误,那么这个字节在传输中一定有错误发生。如果奇偶校验是正确的,那么要么没有发生错误, 要么发生了偶数个的错误。如果用户选择数据长度为 8 位,则因为没有多余的比特可被用来作为奇偶校验位,因此就叫做“无奇偶校验(Non) ”。
停止位(Stop bits): 在每个字节的数据位发送完成之后,发送停止位,来标志着一次数剧传输完成,同时用来帮助接受信号方硬件重同步。 可选择为: 1(默认)、 1.5 或者 2 位。
按照一个完整的字节包括一位起始位、 8 位数据位、 一位停止位即总共十位数据来算,要想完整的实现这十位数据的发送,就需要 11 个波特率时钟脉冲, 第 1 个脉冲标记一次传输的起始, 第 11 个脉冲标记一次传输的结束,如下所示:
Uart_Tx.v
//========================================
// Filename : Uart_Tx.v
// Created On : 2022-2-26
// Last Modified : 2022-2-26
// Author : Ritian73
// Description : Uart_Tx
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//========================================
module Uart_Tx(input Rst_n,input Send_En,input [7:0]Data_Byte,input [2:0]Baud_Set,input Clk_50M,output reg Uart_Tx_Data,output reg Tx_Done
); //波特率选择
reg [15:0]baud_cnt;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)baud_cnt<=16'd5207;else begincase(Baud_Set) //baud_cnt等于波特率周期/时钟周期(20ns) 例9600:104167ns/20ns=52080: baud_cnt <= 16'd5207; //96001: baud_cnt <= 16'd2603; //192002: baud_cnt <= 16'd1301; //384003: baud_cnt <= 16'd867; //576004: baud_cnt <= 16'd433; //115200default baud_cnt<=16'd5207;endcaseend
end
//计数器
reg [15:0]div_cnt;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)div_cnt <= 16'd0;else if(Send_En)beginif(div_cnt == baud_cnt)begindiv_cnt <= 16'd0; endelsediv_cnt <= div_cnt + 1'd1;endelsediv_cnt <= 16'd0;
end
//数据位循环计数
reg [3:0]data_cnt;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)data_cnt <= 4'd0;else if(data_cnt == 4'd10)begindata_cnt <= 4'd0;endelse if(div_cnt == baud_cnt)begindata_cnt <= data_cnt + 1'b1; endelse data_cnt <= data_cnt;
end
//发送完成标志
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)Tx_Done <= 1'd0;else if(data_cnt == 4'd10)beginTx_Done <= 1'd1;endelse Tx_Done <= 1'd0;
end//数据寄存
reg [7:0]Data_Byte_Reg;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)Data_Byte_Reg <= 8'd0;else if(Send_En)beginData_Byte_Reg <= Data_Byte;endelse beginData_Byte_Reg <= Data_Byte_Reg;end
end
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)Uart_Tx_Data <= 1'd1;else begincase(data_cnt) //baud_cnt等于波特率周期/时钟周期(20ns) 例9600:104167ns/20ns=52080: Uart_Tx_Data <= 1'b1; //1: Uart_Tx_Data <= 1'b0; //START2: Uart_Tx_Data <= Data_Byte_Reg[0];3: Uart_Tx_Data <= Data_Byte_Reg[1];4: Uart_Tx_Data <= Data_Byte_Reg[2];5: Uart_Tx_Data <= Data_Byte_Reg[3];6: Uart_Tx_Data <= Data_Byte_Reg[4];7: Uart_Tx_Data <= Data_Byte_Reg[5];8: Uart_Tx_Data <= Data_Byte_Reg[6];9: Uart_Tx_Data <= Data_Byte_Reg[7];10: Uart_Tx_Data <= 1'b1; //STOPdefault Uart_Tx_Data <= 1'b1;endcaseend
end
endmodule
Uart_Tx_Tb.v
`timescale 1ns / 1ps
//========================================
// Filename : Uart_Tx_Tb.v
// Created On : 2022-2-26
// Last Modified : 2022-2-26
// Author : Ritian73
// Description : Uart_Tx_Tb
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//========================================
module Uart_Tx_Tb();reg Rst_n;reg Send_En;reg [7:0]Data_Byte;reg [2:0]Baud_Set;reg Clk_50M;wire Uart_Tx_Data;wire Tx_Done;Uart_Tx Uart_Tx(.Rst_n(Rst_n),.Send_En(Send_En),.Data_Byte(Data_Byte),.Baud_Set(Baud_Set),.Clk_50M(Clk_50M),.Uart_Tx_Data(Uart_Tx_Data),.Tx_Done(Tx_Done)
); initial Clk_50M = 1;always#10 Clk_50M =~Clk_50M;initial beginRst_n = 0;#201;Baud_Set = 3'd2;#201;Send_En = 1;#201;Data_Byte = 8'b01010101;#20100;Rst_n = 1;#200;@(posedge Tx_Done); Send_En = 0;#201;Baud_Set = 3'd4;#201;Data_Byte = 8'b10101010; #10000;Send_En = 1; #200;@(posedge Tx_Done); Send_En = 0;#20000;$stop;end
endmodule
仿真图片
串口接收时序图:
Uart_Rx.v
//=======================================================================
// Filename : Uart_Rx.v
// Author : Ritian73
// Created On : 2022-02-27 21:37
// Last Modified :
// Description :
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//=======================================================================
module Uart_Rx(input Clk_50M,input Rst_n,input Uart_Rx_Data,input [2:0]Baud_Set,output reg[7:0]Data_Byte,output reg Rx_Done
);
//波特率选择
reg [15:0]baud_cnt;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)baud_cnt<=16'd5207;else begincase(Baud_Set) 0: baud_cnt <= 16'd5207; //96001: baud_cnt <= 16'd2603; //192002: baud_cnt <= 16'd1301; //384003: baud_cnt <= 16'd867; //576004: baud_cnt <= 16'd433; //115200default baud_cnt<=16'd5207;endcaseend
end
//单 bit 异步信号同步设计
reg Uart_Rx_Sync1;
reg Uart_Rx_Sync2;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)beginUart_Rx_Sync1 <= 1'b0;Uart_Rx_Sync2 <= 1'b0;endelse beginUart_Rx_Sync1 <= Uart_Rx_Data;Uart_Rx_Sync2 <= Uart_Rx_Sync1;end
end//上升沿检测
reg Uart_Rx_Reg1;
reg Uart_Rx_Reg2;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)beginUart_Rx_Reg1 <= 1'b0;Uart_Rx_Reg2 <= 1'b0;endelse beginUart_Rx_Reg1 <= Uart_Rx_Sync2;Uart_Rx_Reg2 <= Uart_Rx_Reg1;end
endwire Uart_Rx_Negedge;
assign Uart_Rx_Negedge = (!Uart_Rx_Reg1 & Uart_Rx_Reg2) ;reg Uart_Rx_Flag;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)Uart_Rx_Flag <= 1'b0;else if(Uart_Rx_Negedge == 1'b1 && Uart_Rx_Flag == 1'b0 )Uart_Rx_Flag <= 1'b1;else if(Rx_Done == 1'b1)Uart_Rx_Flag <= 1'b0;elseUart_Rx_Flag <= Uart_Rx_Flag;
end//计数器
reg [15:0]div_cnt;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)div_cnt <= 16'd0;else if(Uart_Rx_Flag)beginif(div_cnt == baud_cnt)begindiv_cnt <= 16'd0; endelsediv_cnt <= div_cnt + 1'd1;endelsediv_cnt <= 16'd0;
end//数据位循环计数
reg [3:0]data_cnt;
reg Uart_Rx_Voltage;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)data_cnt <= 4'd0;else if(data_cnt == 4'd10)begindata_cnt <= 4'd0;endelse if(div_cnt == baud_cnt/2)begindata_cnt <= data_cnt + 1'b1;Uart_Rx_Voltage <= Uart_Rx_Sync2; endelse data_cnt <= data_cnt;
end//数据寄存
reg [7:0]Data_Byte_Reg;
always@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)beginData_Byte <= 8'd0;Rx_Done <= 1'b0;endelse if(data_cnt == 4'd10)beginData_Byte <= Data_Byte_Reg;Rx_Done <= 1'b1;endelse beginData_Byte <= Data_Byte;Rx_Done <= 1'b0;end
endalways@(posedge Clk_50M or negedge Rst_n)beginif(!Rst_n)Data_Byte_Reg <= 8'd0;else begincase(data_cnt) 0: ; 1: ;//START2: Data_Byte_Reg[0] <= Uart_Rx_Voltage ;3: Data_Byte_Reg[1] <= Uart_Rx_Voltage ;4: Data_Byte_Reg[2] <= Uart_Rx_Voltage ;5: Data_Byte_Reg[3] <= Uart_Rx_Voltage ;6: Data_Byte_Reg[4] <= Uart_Rx_Voltage ;7: Data_Byte_Reg[5] <= Uart_Rx_Voltage ;8: Data_Byte_Reg[6] <= Uart_Rx_Voltage ;9: Data_Byte_Reg[7] <= Uart_Rx_Voltage ;10: ; //STOPdefault Data_Byte_Reg <= Data_Byte_Reg;endcaseend
end
endmodule
Uart_Rx_Tb.v
`timescale 1ns / 1ps
//=======================================================================
// Filename : Uart_Rx_Tb.v
// Author : Ritian73
// Created On : 2022-02-27 21:37
// Last Modified :
// Description :
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//=======================================================================
module Uart_Rx_Tb();reg Clk_50M;reg Rst_n;reg Uart_Rx_Data;reg [2:0]Baud_Set;wire [7:0]Data_Byte;wire Rx_Done;Uart_Rx Uart_Rx(.Clk_50M(Clk_50M),.Rst_n(Rst_n),.Uart_Rx_Data(Uart_Rx_Data),.Baud_Set(Baud_Set),.Data_Byte(Data_Byte),.Rx_Done(Rx_Done)
); initial Clk_50M = 1;always#10 Clk_50M =~Clk_50M;initial beginRst_n = 0;#1001;Baud_Set = 3'd4; //115200#1001;Uart_Rx_Data = 1'b1;#1001;Rst_n = 1;#1001;Uart_Rx_Data = 1'b0;//START#8680;Uart_Rx_Data = 1'b1;//Bit0#8680;Uart_Rx_Data = 1'b0;//Bit1#8680;Uart_Rx_Data = 1'b1;//Bit2#8680;Uart_Rx_Data = 1'b0;//Bit3#8680;Uart_Rx_Data = 1'b1; //Bit4 #8680;Uart_Rx_Data = 1'b0; //Bit5 #8680;Uart_Rx_Data = 1'b1; //Bit6 #8680;Uart_Rx_Data = 1'b0; //Bit7 #8680;Uart_Rx_Data = 1'b1; //STOP#10000;$stop;end
endmodule
仿真图片
串口回环仿真
Uart.v
`timescale 1ns / 1ps
//=======================================================================
// Filename : Uart.v
// Author : Ritian73
// Created On : 2022-02-28 20:37
// Last Modified :
// Description :
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//=======================================================================
module UART(input Clk_50M,input Rst_n,input Send_En,input [7:0]Data_Byte_In,output [7:0]Data_Byte_Out,output Tx_Done);wire Uart_Tx_Data;
Uart_Tx Uart_Tx(.Rst_n(Rst_n),.Send_En(Send_En),.Data_Byte(Data_Byte_In),.Baud_Set(3'd4),.Clk_50M(Clk_50M),.Uart_Tx_Data(Uart_Tx_Data),.Tx_Done(Tx_Done)
);
Uart_Rx Uart_Rx(.Clk_50M(Clk_50M),.Rst_n(Rst_n),.Uart_Rx(Uart_Tx_Data),.Baud_Set(3'd4),.Data_Byte(Data_Byte_Out),.Rx_Done()
);
endmodule
Uart_Tb.v
`timescale 1ns / 1ps
//=======================================================================
// Filename : Uart_Tb.v
// Author : Ritian73
// Created On : 2022-02-28 20:37
// Last Modified :
// Description :
// Baud_Set baud
// 0 9600
// 1 19200
// 2 38400
// 3 57600
// 4 115200
// Clk 50M
//=======================================================================
module Uart_Tb();reg Clk_50M;reg Rst_n;reg Send_En;reg [7:0]Data_Byte_In;wire [7:0]Data_Byte_Out;wire Tx_Done;UART UART(.Clk_50M(Clk_50M),.Rst_n(Rst_n),.Send_En(Send_En),.Data_Byte_In(Data_Byte_In),.Data_Byte_Out(Data_Byte_Out),.Tx_Done(Tx_Done));initial Clk_50M = 1;always#10 Clk_50M =~Clk_50M;initial beginRst_n = 0;#1001;Data_Byte_In=8'h56;#1001; Rst_n = 1; #1001; Send_En = 1;#1001;@(posedge Tx_Done); #1001;Send_En = 0;#1001;Data_Byte_In=8'h73;#1001;Send_En = 1;#1001;@(posedge Tx_Done); Send_En = 0;#10000;$stop;end
endmodule
仿真图片
缺点:一个数据位只进行了一次采样,而且对起始位停止位未进行数据校验,所以本代码抗干扰能力较差。
待改进:可以进行波特率自动矫正,不用手动设置波特率。
(挖坑,有时间改进)
FPGA三大串行通信接口之UART相关推荐
- (123)FPGA面试题-介绍低速接口(UART、IIC、SPI),SPI有几根线,每根线的作用?(三)
1.1 FPGA面试题-介绍低速接口(UART.IIC.SPI),SPI有几根线,每根线的作用?(三) 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-介 ...
- (一)FPGA之串口通信(UART)
(一)FPGA之串口通信(UART) 回到梦开始的地方,如今回过头来看串口协议,确实清晰了很多,但是奈何好记性不如烂笔头,我还是要重新记录一下学习的知识点,方便查找和学习. 波特率(Band Rate ...
- 基于FPGA实现IIC接口(EEPROM)
1 IIC应用领域 在嵌入式系统开发过程中,IIC占据非常重要的地位.IIC通讯接口能到搭载较多的从设备,从而实现与多个从设备进行通讯,在板级通讯中是一种比较常用的通讯接口.笔者通过IIC接口实现FP ...
- DSP—2812、28335串行通信接口SCI
文章来自:http://blog.csdn.net/wu159632/article/details/7996886 SCI(Serial Communication Interface),即串行通信 ...
- 基于FPGA实现PCI-E接口和DMA控制器设计
随着网络的飞速发展,人们可获取的信息量日益增长,数据的处理及存储速率的要求也越来越高.万兆网(10Gb以太网)的普及,高速存储设备的应用(如DDR2,传输速率可达800M)对系统带宽带来极大的挑战. ...
- TTL/RS232/RS422/RS485串行通信接口区别与波形
TTL/RS232/RS422/RS485通信接口区别与波形 串行通信接口区别 串口数据帧格式 接线图 波形图 串行通信接口区别 TTL/RS232/RS422/RS485指的是电平接口标准,都属于串 ...
- 中国批准AMD收购赛灵思!苏妈花350亿美元集齐CPU\GPU\FPGA三大芯片业务
梦晨 发自 凹非寺 量子位 | 公众号 QbitAI 芯片行业即将迎来一场350亿美元大并购. 收购方AMD,在CPU.GPU上势头正猛:被收购方赛灵思(Xilinx),则是全球第一大FPGA巨头. ...
- tms320lf240x 的串行通信接口
首先需要注意,串行通信模块的寄存器是8位的. 一.串行通信接口的物理结构 1.两个IO引脚 SCIRXD SCI接收数据引脚 SCITXD SCI发送数据引脚 2.一个16位的可编程的波特 ...
- Linux下rgmii接口与fpga相连,FPGA控制RGMII接口PHY芯片88E1512网络通信
一.前言 网络通信中的PHY芯片接口种类有很多,之前接触过GMII接口的PHY芯片RTL8211EG.但GMII接口数量较多,本文使用RGMII接口的88E1512搭建网络通信系统.这类接口总线位宽小 ...
最新文章
- Verilog设计实例(4)详解全类别加法器(一)
- Unity 官方自带的例子笔记 - Space Shooter
- 快速开发基于 HTML5 网络拓扑图应用之 DataBinding 数据绑定篇
- [转]apache MPM介绍
- 厉害了!浙大研发出踹不倒四足机器人“绝影”,中国版波士顿动力来了
- hybrid环境下划分vlan一个实验 ————一故障分析
- 利用openssl进行base64的编码与解码
- C++ string()什么意思
- 液压传动与控制QY-QDSY16
- Matlab中sqrt函数的用法
- WPS表格常用快捷键大全
- Python字符串拼接的四种方法
- 日期抽象数据类型设计与实现作业总结
- python基础—列表解析式简单应用
- win10文件夹加密_Win10 系统优化软件 Windows 10 Manager v3.2.0
- git 怎么回退已经push的版本_git push 操作代码回退
- OD调试常见断点及原理(浓缩版)
- 拆机详解2:比Macintosh还早?苹果Lisa拆解
- 人工智能、深度学习、机器学习常见面试题41~55
- 《多一点爱心》 --《年轻的潮》 汪国真
热门文章
- 【大众点评评论爬虫】一键获取大众点评完整评论工具批量爬取保存为excel数据
- 坚果云显示连接服务器失败怎么办,坚果云提示同步过程中遇到错误,怎么解决?...
- PHP怎样大幅度降低图片大小但最大程度保持图片清晰?
- file_get_contents failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request
- matlab判断星期几的语句,计算某一天是星期几的matlab程序
- react之事件绑定(this、传参)
- 是什么引发了我对知识的渴望
- python中合法的八进制数是_0o12f 是合法的八进制数字。 (2.0分)_学小易找答案
- 汉字转拼音的c++实现
- 每天可以一看的哲理句子