FPGA学习之路—接口(1)—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应用程序设计实例精讲》

原创文章 4 获赞 8 访问量 157

猜你喜欢

转载自blog.csdn.net/qq_42334072/article/details/105862599