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相关推荐

  1. (123)FPGA面试题-介绍低速接口(UART、IIC、SPI),SPI有几根线,每根线的作用?(三)

    1.1 FPGA面试题-介绍低速接口(UART.IIC.SPI),SPI有几根线,每根线的作用?(三) 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)FPGA面试题-介 ...

  2. (一)FPGA之串口通信(UART)

    (一)FPGA之串口通信(UART) 回到梦开始的地方,如今回过头来看串口协议,确实清晰了很多,但是奈何好记性不如烂笔头,我还是要重新记录一下学习的知识点,方便查找和学习. 波特率(Band Rate ...

  3. 基于FPGA实现IIC接口(EEPROM)

    1 IIC应用领域 在嵌入式系统开发过程中,IIC占据非常重要的地位.IIC通讯接口能到搭载较多的从设备,从而实现与多个从设备进行通讯,在板级通讯中是一种比较常用的通讯接口.笔者通过IIC接口实现FP ...

  4. DSP—2812、28335串行通信接口SCI

    文章来自:http://blog.csdn.net/wu159632/article/details/7996886 SCI(Serial Communication Interface),即串行通信 ...

  5. 基于FPGA实现PCI-E接口和DMA控制器设计

    随着网络的飞速发展,人们可获取的信息量日益增长,数据的处理及存储速率的要求也越来越高.万兆网(10Gb以太网)的普及,高速存储设备的应用(如DDR2,传输速率可达800M)对系统带宽带来极大的挑战. ...

  6. TTL/RS232/RS422/RS485串行通信接口区别与波形

    TTL/RS232/RS422/RS485通信接口区别与波形 串行通信接口区别 串口数据帧格式 接线图 波形图 串行通信接口区别 TTL/RS232/RS422/RS485指的是电平接口标准,都属于串 ...

  7. 中国批准AMD收购赛灵思!苏妈花350亿美元集齐CPU\GPU\FPGA三大芯片业务

    梦晨 发自 凹非寺 量子位 | 公众号 QbitAI 芯片行业即将迎来一场350亿美元大并购. 收购方AMD,在CPU.GPU上势头正猛:被收购方赛灵思(Xilinx),则是全球第一大FPGA巨头. ...

  8. tms320lf240x 的串行通信接口

    首先需要注意,串行通信模块的寄存器是8位的. 一.串行通信接口的物理结构 1.两个IO引脚 SCIRXD    SCI接收数据引脚 SCITXD    SCI发送数据引脚 2.一个16位的可编程的波特 ...

  9. Linux下rgmii接口与fpga相连,FPGA控制RGMII接口PHY芯片88E1512网络通信

    一.前言 网络通信中的PHY芯片接口种类有很多,之前接触过GMII接口的PHY芯片RTL8211EG.但GMII接口数量较多,本文使用RGMII接口的88E1512搭建网络通信系统.这类接口总线位宽小 ...

最新文章

  1. Verilog设计实例(4)详解全类别加法器(一)
  2. Unity 官方自带的例子笔记 - Space Shooter
  3. 快速开发基于 HTML5 网络拓扑图应用之 DataBinding 数据绑定篇
  4. [转]apache MPM介绍
  5. 厉害了!浙大研发出踹不倒四足机器人“绝影”,中国版波士顿动力来了
  6. hybrid环境下划分vlan一个实验 ————一故障分析
  7. 利用openssl进行base64的编码与解码
  8. C++ string()什么意思
  9. 液压传动与控制QY-QDSY16
  10. Matlab中sqrt函数的用法
  11. WPS表格常用快捷键大全
  12. Python字符串拼接的四种方法
  13. 日期抽象数据类型设计与实现作业总结
  14. python基础—列表解析式简单应用
  15. win10文件夹加密_Win10 系统优化软件 Windows 10 Manager v3.2.0
  16. git 怎么回退已经push的版本_git push 操作代码回退
  17. OD调试常见断点及原理(浓缩版)
  18. 拆机详解2:比Macintosh还早?苹果Lisa拆解
  19. 人工智能、深度学习、机器学习常见面试题41~55
  20. 《多一点爱心》 --《年轻的潮》 汪国真

热门文章

  1. 【大众点评评论爬虫】一键获取大众点评完整评论工具批量爬取保存为excel数据
  2. 坚果云显示连接服务器失败怎么办,坚果云提示同步过程中遇到错误,怎么解决?...
  3. PHP怎样大幅度降低图片大小但最大程度保持图片清晰?
  4. file_get_contents failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request
  5. matlab判断星期几的语句,计算某一天是星期几的matlab程序
  6. react之事件绑定(this、传参)
  7. 是什么引发了我对知识的渴望
  8. python中合法的八进制数是_0o12f 是合法的八进制数字。 (2.0分)_学小易找答案
  9. 汉字转拼音的c++实现
  10. 每天可以一看的哲理句子