Verilog实现UART之二:发送模块

 1.发送原理:

  当并行数据准备好后,如果得到发送指令,则将数据按UART协议输出,先输出一个低电平的起始位,然后从低到高输出8个数据位,接着是可选的奇偶校验位,最后是高电平的停止位;

  由于发送时钟clk16x为波特率的16倍,因此对clk16x计数到16时,发送D0;计数到32时,发送D1……依此类推;

Verilog实现UART之二:发送模块

2.发送模块代码:

module tx_module(

     input               clk16x,       /*       transmit clock,16×115200                 */

     input               rst_n,        /*        glabol reset signal                     */

     input               TransEn,      /*            transmit enable                     */

     input [7:0]         DataToTrans,  /*        Data prepared for transmitting          */

    

     output reg          BufFull,      /*       Data buffer is full                      */

     output reg          tx            /*           serial data out                      */

);



/*    capture the rising edge of TransEn    */

reg TransEn_r;

wire pos_tri;

always@(posedge clk16x or negedge rst_n)

begin

    if(!rst_n)

        TransEn_r <= 1'b0;

    else

        TransEn_r <= TransEn;

end

assign pos_tri = ~TransEn_r & TransEn;



/*

*    when the rising edge of DataEn comes up, load the Data to buffer

*/

reg [7:0] ShiftReg;

always@(posedge pos_tri or negedge rst_n)

begin

    if(!rst_n)

        ShiftReg <= 8'b0;

    else

        ShiftReg <= DataToTrans;

end

//----------------------------------------------    

/*     counter control      */

reg cnt_en;

always@(posedge clk16x or negedge rst_n)

begin

    if(!rst_n)

        begin

            cnt_en  <= 1'b0;

            BufFull <= 1'b0;

        end

    else if(pos_tri==1'b1)

        begin

            cnt_en  <=1'b1;

            BufFull <=1'b1;

        end

    else if(cnt==8'd160)

        begin

            cnt_en<=1'b0;

            BufFull <=1'b0;

        end

end



//---------------------------------------------

/*      counter module        */

reg [7:0] cnt; 

always@(posedge clk16x or negedge rst_n)

begin

    if(!rst_n)

        cnt<=8'd0;

    else if(cnt_en)

        cnt<=cnt+1'b1;

    else

        cnt<=8'd0;

end



//---------------------------------------------

/*      transmit module        */



always@(posedge clk16x or negedge rst_n)

begin

    if(!rst_n)

        begin

            tx <= 1'b1;

        end

    else if(cnt_en)

        case(cnt)

            8'd0   :  tx <= 1'b0;

            8'd16  :  tx <= ShiftReg[0];

            8'd32  :  tx <= ShiftReg[1];

            8'd48  :  tx <= ShiftReg[2];

            8'd64  :  tx <= ShiftReg[3];

            8'd80  :  tx <= ShiftReg[4];

            8'd96  :  tx <= ShiftReg[5];

            8'd112 :  tx <= ShiftReg[6];

            8'd128 :  tx <= ShiftReg[7];

            8'd144 :  tx <= 1'b1;

        endcase

    else

        tx <= 1'b1;

end



endmodule

测试结果:正确率100%

Verilog实现UART之二:发送模块

3.如需要校验位或其它风格的设计,可以参考Xilinx的发送模块:

module txmit (din,tbre,tsre,rst,clk16x,wrn,sdo) ;



output tbre ;    /*数据缓存区满指示*/

output tsre ;    /*移位寄存器空指示*/

output sdo ;     /*串行数据发送端*/

input [7:0] din ;/*并行数据输入*/

input rst ;      /*复位,高电平有效*/

input clk16x ;   /*发送时钟*/

input wrn ;      /*发送使能,低电平有效*/



reg  sdo ;                 

reg tsre ;              

reg tbre ;  

         











reg[3:0] clkdiv ;

wire clk1x ;



reg [3:0] no_bits_sent ;





/*捕获发送使能的下降沿*/

reg wrn1 ;

reg wrn2 ;

always @(posedge clk16x or posedge rst)

begin

    if (rst)

        begin

            wrn1 <= 1'b1 ;

            wrn2 <= 1'b1 ;

        end

    else 

        begin

            wrn1 <= wrn ;

            wrn2 <= wrn1 ;

        end

end





/*    计数控制模块    */



reg clk1x_enable ;   /*发送时钟允许信号*/

always @(posedge clk16x or posedge rst)

begin

    if (rst)

        begin

            tbre <= 1'b0 ;

            clk1x_enable <= 1'b0 ;

        end

    else if (!wrn1 && wrn2)     /*如果捕获到使能信号的下降沿,则开始计数*/

        begin

            clk1x_enable <= 1'b1 ;

            tbre <= 1'b1 ;        /*数据缓存区满标志置1*/

        end

    else if (no_bits_sent == 4'b0010)

            tbre <= 1'b1 ;

    else if (no_bits_sent == 4'b1101)

        begin

            clk1x_enable <= 1'b0 ;

            tbre <= 1'b0 ;

        end

    end



/*    使能信号的下降沿,载入输入数据到缓冲区*/

reg [7:0] tbr ;    

always @(negedge wrn or posedge rst)

begin

    if (rst)

        tbr = 8'b0 ;

    else

        tbr = din ;

end





/*16分频,产生发送时钟*/

always @(posedge clk16x or posedge rst)

begin

    if (rst)

        clkdiv = 4'b0 ; 

    else if (clk1x_enable)

        clkdiv = clkdiv + 1 ;

end



assign clk1x = clkdiv[3] ;



/*  计数模块   */

always @(posedge clk1x or posedge rst or negedge clk1x_enable)

if (rst) 

    no_bits_sent = 4'b0000 ;

else if (!clk1x_enable)

    no_bits_sent = 4'b0000 ;

else

    no_bits_sent = no_bits_sent + 1 ;





/*        发送模块        */

reg [7:0] tsr ;    /*发送移位寄存器*/

reg parity ;        /*   校验位   */

always @(negedge clk1x or posedge rst)

    if (rst)

        begin

            sdo <= 1'b1 ;

            tsre <= 1'b1 ;

            parity <= 1'b1 ;

            tsr <= 8'b0 ;

        end

    else

        begin

            if (no_bits_sent == 4'b0001)

                begin

                    tsr <= tbr ;            //将缓冲区中的数据载入到移位寄存器

                    tsre <= 1'b0 ;

                end

            /*start bit*/

            else if (no_bits_sent == 4'b0010)

                begin

                    sdo <= 1'b0 ;    

                end

             /*Data bits */

            else if ((no_bits_sent >= 4'b0011) && (no_bits_sent <= 4'b1010))

                begin

                    tsr[7:1] <= tsr[6:0] ;

                    sr[0] <= 1'b0 ;

                    sdo <= tsr[7] ;

                    parity <= parity ^ tsr[7] ;

                end

            /*  校验位  */

            else if (no_bits_sent == 4'b1011)

                begin

                    sdo <= parity ;

                end

            else if (no_bits_sent == 4'b1100)

                begin

                    sdo <= 1'b1 ;

                    tsre <= 1'b1 ;

                end

        end



endmodule

 

 

你可能感兴趣的:(Verilog)