FPGA学习之路——URAT Verilog程序设计
FPGA学习之路——URAT Verilog程序设计
UART(Universal Asynchronous Receiver Transmitter,通用异步收发器)是广泛使用的异步串行数据通信协议。
UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。
- Tx—数据发送接口
- Rx—数据接收接口
两个设备间将TX与RX相连,RX与TX相连即可正常工作。最常用到的就是我们电脑上的USB那就是个最典型的UART接口。
UART传输时序
UART传输时序图如下图所示
发送数据过程: 空闲状态,线路位于高电平;当接收到发送数据指令后,拉低线路一个数据位的时间T,接着数据按低位到高位依次发送,数据发送完毕后,接着发送奇偶校验位和停止位(停止位为高电平),一帧数据发送完毕。
接收数据过程: 空闲状态,线路处于高电平;当检测到线路的下降沿(线路点位由高电位变为低电位)时说明线路有数据传输,按规定的波特率从低位到高位接收数据,数据接收完毕后,接着接收并比较奇偶校验位是否正确,若正确则通知后续设备准备接收或存入缓存。
因为UART是异步传输,没有同步时钟。所以为了保证数据传输的正确性,UART采用16倍数据波特率的时钟进行采样。每个数据有16个时钟采样,取中间的采样值。
UART的接收数据时序为:当检测到数据的下降沿时,表明线路上有数据在传输,这时计数子CNT开始计数,当计数器为24=16+8(去除开始的拉低数据,在第0位数据中间采样)时,采样的值为第0位数据;当计数子的值为40时,采样的为第一位数据,以此类推。若进行奇偶校验,则当计数子的值为152时,采样的值即为奇偶位;当计数子的值为168时,采样的值“1”表示停止位,表示一帧数据接收完成。
假设数据的波特率为b,那么时钟频率就是16b。以b=115200,系统时钟为50MHz为例,则分频系数为50,000,000/(16115200)=27.127,取整为27。分频器Verilog HDL代码如下:
module clkdiv(clk,rst,clkout);
input clk;
input rst;
output clkout;
reg clkout;
reg [15:0] cnt;
always @(negedge rst)begin
clkout<=1'd1;
cnt<=16'd0;
end
always @(posedge clk)begin
if(cnt==16'd12)begin
clkout<=1'd1;
cnt<=cnt+16'd1;
end
else if(cnt==16'd26)begin
clkout<=1'd0;
cnt<=16'd0;
end
else begin
cnt<=cnt+16'd1;
end
end
endmodule
编码过程中需注意,若部分寄存器不通过rst赋初值,如代码块中的cnt和clk_out,则Vivado会报错,Vivado版本为2018.3,目前我也只想到引入rst进行赋值的方法解决。
更:可以在定义寄存器时直接赋初值。如reg [7:0]cnt =8’d0;
此外,UART发送和接受模块中部分代码如下,完整代码我稍后上传至CSDN,有需的朋友可以下载参考。
上升沿检测代码,其中wrsig发送命令,上升沿有效。该部分代码完成了wrsig的上升沿检测。
always @(posedge clk)begin
wrsigbuf<=wrsig;
wrsigrise<=(~wrsigbuf)&wrsig;
end
启动数据发送进程的代码,需满足发送命令有效且线路空闲的条件
always @(posedge clk)begin
if(wrsigrise && (~idle))begin //发送命令有效且线路空闲,启动数据发送进程
send<=1'd1;
end
else if(cnt == 8'd176)begin //一帧数据发送结束
send<=1'd0;
end
end
数据发送进程中的部分代码,设计思路在上文中已表述,其中paritymode为常数0,用于奇偶校验;datain为待传输的数据;presult存放数据校验的结果;cnt为32—112的被省略。在cnt为144时发送奇偶校验位,然后拉高电平,表示传输过程结束。接收进程编码思路与发送进程类似,此处不表。
always @(posedge clk)begin
if(send == 1'd1)begin
case(cnt)
8'd0:
begin
tx<=1'd0;
idle<=1'd1;
cnt<=cnt+8'd1;
end
8'd16:
begin
tx<=datain[0];
presult<=datain[0]^paritymode;
idle<=1'b1;
cnt<=cnt+8'd1;
end
……
8'd128:
begin
tx <= datain[7];
presult <= datain[7]^presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd144:
begin
tx<=presult;
idle <= 1'b1;
cnt <= cnt + 8'd1;
end
8'd160:
begin
tx<=1'd1;
idle<=1'd1;
cnt<=cnt+1'd1;
end
8'd176:
begin
tx<=1'd1;
idle<=1'd0;
cnt<=cnt+8'd1;
end
default:
begin
cnt<=cnt+8'd1;
end
endcase
end
else begin
tx<=1'd1;
cnt<=8'd0;
idle<=1'b0;
end
end
本文搭建的系统结构图如下,clkdiv为分频模块;testuart为激励产生模块,输出待发送的数据和发送使能;uarttx为uart发送模块,输入为分频后的时钟、待发送的数据和发送使能,输出为数据信号tx和idle,idle为线路指示状态,高为线路忙,低为空闲;uartrx为uart接收模块,输入为分频后的时钟和数据信号,输出为数据、数据出错指示和帧出错指示。
本文搭建系统的仿真结果如下图所示:
从图中我们可以看到,接受数据与发送数据结果相同。若接收数据的奇偶校验位与收到的奇偶校验位不符,则dataerror为1。若接收帧的第11位即停止位不为1,则帧发生错误,frameerror为1。文中结果均未发生错误。
项目下载链接:https://download.csdn.net/download/qq_42334072/12376984
参考资料:《VERILOG HDL应用程序设计实例精讲》