首页 > 技术 > 内容

浅谈UART通信协议 UART接收数据时序设计

时间:2025-11-29  作者:Diven  阅读:0

串口通信也是一个基础实验,是FPGA与电脑、单片机DSP通信的最简单的方案,对通信速率要求不高时可以选择UART通信。您可能已经知道UART时序的控制、波特率的配置等方面的内容,但在实际使用时还是会遇到一些问题,比如如何才能恰当的和其模块进行衔接?为什么时序明明没问题,却无法和其控制单元成功通信?本文致力于全面解析在设计UART通信时的思路方法。

UART通信协议

UART通信的一帧一般由11到12位数据组成。1bit的起始位,检测为低电平表示数据开始传输;紧接着8bits的数据;然后是1bit的奇偶校验位,可以是奇校验或者偶校验;最后是1bit或2bits的停止位,必须为高电平,表示一个字符数据的传输结束。

其中校验位是可选的,用来检验数据是否传输正确。如果有校验位,则需要保证收发双方选择同样的检验方式。奇校验就是保证数据中的1是奇数,比如如果8bit数据中有3bits的1,校验位置0;如果有4bits的1,校验位置1。偶校验就是保证数据中的1是偶数。

 

波特率的配置

波特率表示数据传输的速率,单位bps,表示位每秒。比如9600bps就表示1s可以传输9600bits的数据。异步收发没有时钟打拍来控制数据的传输,就需要保证收发双方在波特率设置上的一致。确保接收数据的完整性。

程序中通常使用16倍速率对UART通信时序进行采样,则UART通信所需的时钟就是16*bps,如9600bps通信所需的驱动时钟大小就是16*9600=153.6kHz。程序中可以使用一个计数器对系统时钟分频产生UART通信时钟。

// 分频生成UART通信时钟

always @(posedge clk50 or negedge rst_n)

if (!rst_n) begin

clkout 《=1‘b0;

cnt《=0;

end

else if(cnt == 16’d162) begin //近似50%占空比

clkout 《= 1‘b1;

cnt 《= cnt + 16’d1;

end

else if(cnt == 16‘d325) begin //50M/(16*9600)

clkout 《= 1’b0;

cnt 《= 16‘d0;

end

else cnt 《= cnt + 16’d1;

UART发送数据时序设计

通常我们程序中都会设计一个UART发送数据的开始信号,对这个开始信号的处理方法和“FPGA基础设计(二):PS2键盘控制及短按、长按”这篇文章对按键有效信号处理的方法相同,采用一级寄存,然后进行逻辑判断,从而产生一个时钟宽度的有效信号。那么当检测到有效信号时便可以启动UART发送数据的过程。

// 检测发送命令wrsig的上升沿

always @(posedge clk)

begin

wrsiGBUf 《= wrsig;

wrsigrise 《= (~wrsiGBUf) & wrsig;

end

// 启动串口发送程序

always @(posedge clk)

if (wrsigrise && (~idle)) //当发送命令有效且线路为空闲时,启动新的数据发送进程

send 《= 1‘b1;

else if(cnt == 8’d168) //一帧数据发送结束

send 《= 1‘b0;

UART是按单bit发送的,因此在控制时序时可以使用一个计数器控制,在对应的计数位送出对应的数据。由于我们使用的是16倍时钟采样,因此每个数据位之间的计数间隔便是16,一次完整的发送过程如下所示:

// 串口发送程序, 16个时钟发送一个bit

always @(posedge clk or negedge rst_n)

begin

if (!rst_n) begin

tx 《= 1’b0;

idle 《= 1‘b0;

cnt《=8’d0;

presult《=1‘b0;

end

else if(send == 1’b1) begin

case(cnt) //产生起始位

8‘d0: begin

tx 《= 1’b0;

idle 《= 1‘b1;

cnt 《= cnt + 8’d1;

end

8‘d16: begin

tx 《= datain[0]; //发送数据0位

presult 《= datain[0]^paritymode;

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d32: begin

tx 《= datain[1]; //发送数据1位

presult 《= datain[1]^presult;

idle 《= 1‘b1;

cnt 《= cnt + 8’d1;

end

8‘d48: begin

tx 《= datain[2]; //发送数据2位

presult 《= datain[2]^presult;

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d64: begin

tx 《= datain[3]; //发送数据3位

presult 《= datain[3]^presult;

idle 《= 1‘b1;

cnt 《= cnt + 8’d1;

end

8‘d80: begin

tx 《= datain[4]; //发送数据4位

presult 《= datain[4]^presult;

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d96: begin

tx 《= datain[5]; //发送数据5位

presult 《= datain[5]^presult;

idle 《= 1‘b1;

cnt 《= cnt + 8’d1;

end

8‘d112: begin

tx 《= datain[6]; //发送数据6位

presult 《= datain[6]^presult;

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d128: begin

tx 《= datain[7]; //发送数据7位

presult 《= datain[7]^presult;

idle 《= 1‘b1;

cnt 《= cnt + 8’d1;

end

8‘d144: begin

tx 《= presult; //发送奇偶校验位

presult 《= datain[0]^paritymode;

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d160: begin

tx 《= 1‘b1; //发送停止位

idle 《= 1’b1;

cnt 《= cnt + 8‘d1;

end

8’d168: begin

tx 《= 1‘b1;

idle 《= 1’b0; //一帧数据发送结束

cnt 《= cnt + 8‘d1;

end

default: begin

cnt 《= cnt + 8’d1;

end

endcase

end

else begin

tx 《= 1‘b1;

cnt 《= 8’d0;

idle 《= 1‘b0;

end

end

UART接收数据时序设计

UART接收数据的过程和发送数据的过程是恰好相反的。区别只在于UART发送的开始信号和发送数据端tx是从FPGA内部的其模块产生的;而UART接收的开始信号和接收数据段rx送来的数据来自其设备,因此需要对外部送来的信号进行监测。

一帧数据的开始位是低电平有效,因此当检测到rx线上的下降沿时就表示数据通信的开始:

always @(posedge clk) //检测线路的下降沿

begin

rxbuf 《= rx;

rxfall 《= rxbuf & (~rx);

end

// 启动串口接收程序

always @(posedge clk)

if (rxfall && (~idle)) //检测到线路的下降沿并且原先线路为空闲,启动接收数据进程

receive 《= 1‘b1;

else if(cnt == 8’d168) //接收数据完成

receive 《= 1‘b0;

接收数据的过程和发送一样,用一个计数器来控制,这里不再赘述。

发送与接收数据的打包

UART一次通信只能完成一帧,即传输一个8bits的数据,然而我们通常需要很多帧来组成一次完整的通信。如简单常用的气象采集站通信格式为:“FF(开始帧)+雨量+温度+湿度+气压+风速+风向+CRC校验+FE(结束帧)”。这种情况下可以建立一组寄存器专门存储发送或接收的数据。比如发送时可以做如下处理:

//存储待发送的串口信息

reg [7:0] uart_ad [7:0]; //存储发送字符

always @(clk)

begin //定义发送的字符

if(uart_stat==3‘b000) begin

uart_ad[0]《=8’hFF;

uart_ad[1]《=rain;

uart_ad[2]《=temp;

uart_ad[3]《=humi;

uart_ad[4]《=winddir;

uart_ad[5]《=winDSPeed;

uart_ad[6]《=CRC16;

uart_ad[7]《=8‘hFE;

end

end

接收的原理类似,只不过接收是在通信过程中接收。这样我们使用一个计数器控制,并检测串口通信的状态,依次将这组寄存器中的值按发送顺序传入UART发送数据模块即可。

另外需要做好的一件事就是串口模块与其模块的衔接。我们在建立好上述的寄存器组之后,只要把数据来源填充到寄存器组中对应的位置即可。但如果数据是从RAM、FIFO等模块中来的,在串口通信时就应该对使能信号、FIFO空满信号等做出合理的判断和控制,就像“FPGA数据采集-传输-显示系统(一):1.2/50μs冲击电压测量与显示”和“FPGA数据采集-传输-显示系统(二):基于FPGA的温度采集和以太网传输”两篇文章中做的一样。

猜您喜欢


当今电子设备日益追求节能环保的时代,高效的电源转换技术显得尤为重要。LLC谐振转换器作为一种高频、高效的电源转换拓扑结构,近年来备受关注。而带同步整流的LLC电...
2024-06-30 00:00:00
保险丝作为重要的过载保护元件是关键配件。岚珊保险丝因其高品质的性能和多样的规格,广受市场欢迎。本文将围绕“岚珊保险丝体积的规格及品牌”展开,详细介绍其核心规格参...
2024-01-06 01:06:30
DVI连接器(数字视频接口)是应用于视频传输的接口标准,主要用于连接计算机和显示器。其应用领域涵盖了多个行业和场景。在计算机领域,DVI连接器常用于台式机和笔记...
2016-05-14 00:00:00
0 引言2008年ARIKAN E提出了信道极化的概念并对信道极化现象进行了详细的描述[1]。极化码的主要过程是在编码系统中通过对信道进行结合与拆分,然后在其...
2019-01-06 11:19:00
0603贴片电阻,因其尺寸仅为0.6mm*0.3mm,肉眼识别其阻值非常困难。 这时,丝印就显得尤为重要。丝印是印制在电阻表面的数字和字母组合,代表了电阻的阻值...
2024-11-26 11:29:50
锂离子电池电容是现代科技中重要的元件。被应用于手机、笔记本、以及电动车等设备。锂离子电池电容具有高能量密度和长循环寿命等优点。本文将深入探讨锂离子电池电容的几个...
2025-03-22 06:01:39
发光二极管(LED)是应用于照明、显示和信号指示的电子元件。在使用LED时,了解其导通电压是非常重要的。导通电压不仅影响LED的亮度和效率,还以驱动电路的设计密...
2025-04-07 06:01:39
LED点阵屏是现代显示技术中常见的,其主要区别体现在以下几个方面。LED点阵屏的像素间距不同,像素间距小的屏幕适合于近距离观看,显示效果更为清晰;而像素间距大的...
2010-04-25 00:00:00
谐振电感线圈在工作时,常常会出现过热现象。这会影响设备的性能和寿命。下面将介绍一些解决谐振电感线圈过热的方法。降低工作频率谐振电感线圈在高频下工作时,容易发热。...
2025-03-22 05:01:39