FPGA-串口发送模块

------------恢复内容开始------------

  通用异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART)是一种异步收发传输器,其在数据发送时将并行数据转换成串行数据来传输,在数据接收时将接收到的串行数据转换成并行数据,可以实现全双工传输和接收。它包括了 RS232、RS449、RS423、 RS422 和 RS485 等接口标准规范和总线标准规范。换句话说,UART 是异步串行通信的总称。而 RS232、RS449、RS423、RS422 和 RS485 等,是对应各种异步串行通信口的接口标准和总线标准,它们规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容。

  

图1  串口发送时序图

图2 串口发送逻辑框图

  根据选择的波特率计算出相应的波特率时钟,如115200的波特率对应的波特率时钟周期为8680ns,50M时钟对应下时钟计时数为433。波特率时钟周期计时器为div_cnt。波特率时钟计数器为bps_cnt,记录波特率时钟的个数。send_en为发送标志,当send_en时,开始发送数据,数据发送依据bps_cnt的数值来进行,由于串口发送协议起始位之前需为1,因此bps_cnt=0时,uart_tx=1;bps_cnt=1-10时,uart_tx依次等于起始位、数据位、停止位,为了确保停止位保持一位的高电平,bps_cnt=11时,uart_tx=1,因此bps_cnt在0-11内循环,bps_cnt=11时立即清零。为了让send_en信号出现后能立即开始发送数据,设置div_cnt每次为0时,bps_cnt就+1。十位数据发送完成后,tx_done拉高,同时send_en拉低,标志发送完毕。

  利用串口发送模块实现一个每隔10ms,计数加1的计数器。计数从0开始,通过send_en和tx_done信号配合,当count_10ms开始计数时,send_en信号拉高,直到tx_done信号到来时拉低,每当tx_done信号到来时,计时数+1。

串口发送模块代码:

module urat_tx(
    input  wire                         clk                        ,
    input  wire                         rstn                       ,
    input  wire        [   2:0]         baudrate                   ,
    input  wire        [   7:0]         data                       ,
    input  wire                         ena                        ,
    output reg                          tx                         ,
    output reg                          tx_done                     
    );
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++\
//++++++++++++++++  Parameter & Signal  +++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++/
reg                    [  12:0]         baud_clock                 ;
reg                    [  12:0]         div_cnt                    ;
reg                    [   3:0]         bps_cnt                    ;
//reg                                     ena                        ;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++\
//++++++++++++++++  Main code  ++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++/
always @(*) begin                                                   //baudrate choose
        case (baudrate)
            3'd0:baud_clock<=13'd433;
            3'd1:baud_clock<=13'd867;
            3'd2:baud_clock<=13'd1301;
            3'd3:baud_clock<=13'd2603;
            3'd4:baud_clock<=13'd5207;
            default: baud_clock<=13'd433;
        endcase
end

always @(posedge clk or negedge rstn) begin                         //div_cnt
    if(!rstn)
        div_cnt<=0;
    else if(ena)begin
        if(div_cnt==baud_clock)
            div_cnt<=0;
        else
            div_cnt<=div_cnt+1'b1;
    end
    else
        div_cnt<=0;
end

always @(posedge clk or negedge rstn) begin                         //bps_cnt
    if(!rstn)
        bps_cnt<=0;
    else if(ena)begin
        if(div_cnt==0)
        begin
            if(bps_cnt==11)
                bps_cnt<=0;
            else
                bps_cnt<=bps_cnt+1'b1;
        end
    end
        else
            bps_cnt<=0;
end

always @(posedge clk or negedge rstn) begin
    if(!rstn)
        tx<=0;
    else begin
        case (bps_cnt)
            0:tx<=1;
            1:tx<=0;
            2:tx<=data[0];
            3:tx<=data[1];
            4:tx<=data[2];
            5:tx<=data[3];
            6:tx<=data[4];
            7:tx<=data[5];
            8:tx<=data[6];
            9:tx<=data[7];
            10:tx<=1;
            11:tx<=1;
            default:tx<=1;
        endcase
    end
end

always @(posedge clk or negedge rstn) begin                         //tx_done
    if(!rstn)
        tx_done<=0;
    else if((bps_cnt==11)&&(div_cnt==1))
        tx_done<=1;
    else
        tx_done<=0;
end

/*always @(posedge clk or negedge rstn) begin                       //ena
    if(!rstn)
        ena<=0;
    else if(bps_cnt==0)
        ena<=1;
    else if(tx_done)
        ena<=0;
end*/
endmodule

每隔10ms计数器代码:

module uart_tx_count(
    clk,
    rstn,
    tx
    );
    input                               clk                        ;
    input                               rstn                       ;
    output                              tx                         ;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++\
//++++++++++++++++  Parameter & Signal  +++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++/
reg                    [   7:0]         data                       ;
wire                                    tx_done                    ;
reg                                     ena                        ;
reg                    [  18:0]         count_10ms                 ;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++\
//++++++++++++++++  Main code  ++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++/
urat_tx urat_tx_inst(
    .clk                               (clk                       ),
    .rstn                              (rstn                      ),
    .baudrate                          (3'd0                      ),
    .data                              (data                      ),
    .ena                               (ena                       ),
    .tx                                (tx                        ),
    .tx_done                           (tx_done                   ) 
);

always @(posedge clk or negedge rstn) begin                         //count_10ms
    if(!rstn)
        count_10ms<=0;
    else if(count_10ms==499999)
        count_10ms<=0;
    else
        count_10ms<=count_10ms+1'b1;
end

always @(posedge clk or negedge rstn) begin                         //ena
    if(!rstn)
        ena<=0;
    else if(count_10ms==1)
        ena<=1;
    else if(tx_done)
        ena<=0;
end

always @(posedge clk or negedge rstn) begin
    if(!rstn)
        data<=0;
    else if(tx_done)
        data<=data+1'b1;
end
endmodule

testbench代码:

`timescale 1ns / 1ns
module urat_tx_count_tb();
reg clk;
reg rstn;
wire tx;
uart_tx_count u_uart_tx_count(
    .clk  (clk  ),
    .rstn (rstn ),
    .tx   (tx   )
);
initial clk=1;
always#10 clk=!clk;
initial begin
    rstn=0;
    #201;
    rstn=1;
    #10000000;
    $stop;
end
endmodule

Vivado仿真结果:

 

 可以看到10ms计数周期中,只有发送信号时,ena信号才为高电平,发送结束标志信号tx_done到来后拉低,计数值加1。

posted @ 2022-04-17 12:32  Real马锥  阅读(230)  评论(0编辑  收藏  举报