串口系列知识分享:
(1)串口通信实现-串口发送
(2)串口通信发送多字节数据
(3)串口通信实现-串口接收
(4)UART 通信-使用VIO进行板级验证
(5)串口接收-控制LED闪烁
(6)使用串口发送实现ACX720开发板时钟显示
(7)串口发送+RAM+VGA传图


前言

此文介绍uart串口协议(串口发送)的verilog实现和testbench的编写,仿真环境为vivado 2018.3。


提示:以下是本篇文章正文内容,下面案例可供参考

一、串口通信协议(uart)

串口作为常用的三大低速总线(UART、SPI、IIC)之一,在设计众多通信接口和调试时占有重要地位。串口(UART)全称通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),主要用于数据间的串行传递,是一种全双工传输模式。它在发送数据时将并行数据转换成串行数据来传输,在接收数据时将接收到的串行数据转换成并行数据。(具体应用可自行百度)

二、串口发送的时序图

UART 在发送或接收过程中的一帧数据由4部分组成,起始位、数据位、奇偶校验位和停止位,如上图所示。其中,起始位标志着一帧数据的开始,停止位标志着一帧数据的结束,数据位是一帧数据中的有效数据。

    起始位:起始位标志。低有效。

    数据位:一帧数据中的有效数据。注意,串口协议规定了数据位长度只能位 6 7 8 位。要想发多位数据,只能将其切分为多个过程发送。

    奇偶校验位:是用来验证数据的正确性。奇偶校验一般不使用,如果 使用,则既可以做奇校验(Odd)也可以做偶校验(Even)。其实就是发的时候如果奇校验位为1,表面数据中1的个数为奇数个,再看接受端的奇校验位是否依旧为1。如果是的话,校验成功。在一定概率上保证了传输的正确性。当然,只是概率上的传输正确。此次试验不同奇偶校验。

    停止位:停止位标志着一帧数据的结束,高有效。

    空闲时,传输 1 。

    波特率设置 : 由于是异步通信,所以没有一个统一的时钟,需要双方约定传输传输速率。常见的波特率有:300, 1200, 2400, 9600, 19200, 115200 等.即一秒发送多少位数据。

    所以我们需要实现下面的时序图。当使能信号到来时,发送起始位,数据位,停止位,一帧数据发送结束。

三、uart_byte_tx模块

module uart_byte_tx(
    Clk,
    Reset_n,
    Data,
    Send_Go,    // 改成单脉冲启动信号  启动一个内部 send_en 信号
    Baud_set,
    uart_tx,
    Tx_done
);
    input Clk;
    input Reset_n;
    input [7:0]Data;
    input Send_Go;
    input [2:0]Baud_set;
    output reg uart_tx;
    output reg Tx_done;
    
    //Baud_set = 0   就让波特率 = 9600;
    //Baud_set = 1   就让波特率 = 19200
    //Baud_set = 2   就让波特率 = 38400;
    //Baud_set = 3   就让波特率 = 57600;   
    //Baud_set = 4   就让波特率 = 115200; 

    reg [17:0]bps_DR;
    always@(*)
        case(Baud_set)
            0:bps_DR = 1000000000/9600/20;
            1:bps_DR = 1000000000/19200/20;
            2:bps_DR = 1000000000/38400/20;
            3:bps_DR = 1000000000/57600/20;
            4:bps_DR = 1000000000/115200/20;
            default:bps_DR = 1000000000/9600/20;
         endcase

    reg Send_en;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)       
        Send_en <= 0;
    else if(Send_Go)
        Send_en <= 1;
    else if(Tx_done)
        Send_en <= 0;
        
    reg [7:0]r_Data;
    always@(posedge Clk)     //进行数据寄存,防止当Send_Go脉冲出现时,Data数据发生偏差
    if(Send_Go)
        r_Data <= Data;
    else
        r_Data <= r_Data;     

    wire bps_clk;
    assign bps_clk = (div_cnt == 1);
    
    reg [17:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        div_cnt <= 0;
    else if(Send_en)begin
        if(div_cnt == bps_DR - 1)
            div_cnt <= 0;
        else 
            div_cnt <= div_cnt + 1'b1;
    end
    else
        div_cnt <= 0;

    reg [3:0]bps_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        bps_cnt <= 0;
    else if(Send_en)begin
        if(bps_clk)begin
            if(bps_cnt == 11)
                bps_cnt <= 0;
            else
                bps_cnt <= bps_cnt + 1'b1;
        end
    end
    else
        bps_cnt <= 0;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        uart_tx <= 1'b1;
    end
    else begin
        case(bps_cnt)
            1:uart_tx <= 0;
            2:uart_tx <= r_Data[0];
            3:uart_tx <= r_Data[1];
            4:uart_tx <= r_Data[2];
            5:uart_tx <= r_Data[3];
            6:uart_tx <= r_Data[4];
            7:uart_tx <= r_Data[5];
            8:uart_tx <= r_Data[6];
            9:uart_tx <= r_Data[7]; 
            10:uart_tx <= 1;
            11:begin uart_tx <= 1;end
            default:uart_tx <= 1;
        endcase
     end
     
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Tx_done <= 0;
    else if((bps_clk == 1)  && (bps_cnt == 10))
        Tx_done <= 1;
    else
        Tx_done <= 0;

endmodule

四、uart_tx_test模块

此模块用于对uart_byte_tx模块进行测试,将uart_byte_tx模块中的Data输入设为每次发送加1。即第一次发送8’d0,第二次发送8’d1,依次加1发送。

module uart_tx_test(
    Clk,
    Reset_n,
    uart_tx,
);
    input Clk;
    input Reset_n;
    output uart_tx;
    
    reg Send_Go;
    reg [7:0]Data;
    
    uart_byte_tx uart_byte_tx(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Data(Data),
        .Send_Go(Send_Go),
        .Baud_set(3'd4),
        .uart_tx(uart_tx),
        .Tx_done(Tx_done)
    );
    
    reg [24:0]counter;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        counter <= 0;
    else if(counter == 4999999)        //每10ms发送一次数据
        counter <= 0;
    else
        counter <= counter + 1;
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)       
        Send_Go <= 0;
    else if(counter == 1)
        Send_Go <= 1;
    else
        Send_Go <= 0;

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)        
        Data <= 0;
    else if(Tx_done)
        Data <= Data + 1'b1;   
    
endmodule

五、TB文件

`timescale 1ns / 1ps

module uart_tx_test_tb();
    reg Clk;
    reg Reset_n;
    wire uart_tx;
    
     uart_tx_test uart_tx_test(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .uart_tx(uart_tx)
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #50000000;    
    end

endmodule

六、仿真波形展示

【附件:】链接:https://pan.baidu.com/s/1KNI2lWvdekhcJ-VJukWNeg?pwd=78h6
提取码:78h6