44,UART串口发送器的分析实现

 

上集一起学习了异步串口收发器UART的电平,波特率,校验位,等内涵知识点,以及RS232,RS485,RS422等基于异步串口的实际通讯总线。

 

这一集我们一起来写一个简单的UART发送器,所以先回忆一下之前说的一个字节的格式:

我们下面的工作就是“画”出这个波形来。

直接分析代码,注意重要知识点:

  1. 需要一个慢的“时钟”,我们可以先用一个计数器,从0-N这样来回循环计数,当等于其中某一数值的时候,就是走了一轮,就是用了(N+1)个周期。这样我们提取计数器等于某一(0-N)内数值的条件,就可以作为(N+1)周期的同步使能信号了:

 

reg [3:0] cnt;

wire bit_syn  = (cnt==9) ;

always @(posedge clk)if ( ~nrst ) cnt_clk <= 0 ;else  cnt <= ( cnt == 9) ? 0:( 1 + cnt) ;

always @(posedge clk ) if (bit_syn)  LED<=LED+1; 这样实现效果。

 

  1. 这里感受一下程序状态机的用法。是一种非常好的实现串行操作序列的方法。这里有个核心本质要把握,1,根据当前状态和输入或者状态条件确定下一个状态。2,根据当前状态,输入或者其他状态条件确定输出。程序状态机编写的时候可以不必太在意状态码,如果必要,编写往后再进行优化。

 

  1. 存在问题:波特率可能会存在可累积误差。
    `timescale 1ns/1ns 
    
    
    /*
     uart_tx #(    .BAUDRATE(115200),    .FREQ(200_000_000))  I_uart_tx (
        .clk(clk), 
        .nrst(nrst),
        .wr(wr),
        .din(din),
        .tx(tx) ,
        .rdy(rdy),
        .parity_type(parity_type)
        );
    */
    
    module uart_tx #(
        parameter BAUDRATE = 115200, 
        parameter FREQ = 200000000
    	)(
        input clk, nrst,
    	
    	input wr,
        input [7:0] din,
    	output reg rdy,
        input[1:0] parity_type , 
    	
        output reg tx 
        
        );
    	reg [7:0] din_save ;	
    	/*
    	parity_type 
    	0: NONE 
    	1: ODD
    	2: EVEN 
    	*/
    	
    //  wire if_byte_is_odd = din[0] +  din[1] +  din[2] +  din[3] +  din[4] +  din[5] +  din[6] +  din[7]  ;  // 1
    //  wire if_byte_is_odd = din[0] ^  din[1] ^ din[2] ^  din[3] ^  din[4] ^  din[5] ^  din[6] ^  din[7]  ;  //  2
    wire if_byte_is_odd = ^din[7:0];
    
    reg [31:0] cnt_clk ;
    wire bit_syn  = cnt_clk == (FREQ/BAUDRATE-1) ;
    
    always @(posedge clk)if ( ~nrst ) cnt_clk <= 0 ;else   cnt_clk <= (bit_syn) ? 0:( 1 + cnt_clk) ;
    
    reg [7:0] st ;
    always@(posedge clk) if (~nrst) st<=0;  else case (st)
    0  :      if (   wr  )begin  din_save<=din ;  st<=1;end   
    1  :      if (bit_syn) st<=2 ;  // syn to bit_syn 
    2  :      if (bit_syn) st<=3;   // start  bit 
    3  :      if (bit_syn) st<=4;   // send bit 0
    4  :      if (bit_syn) st<=5;   // send bit 1
    5  :      if (bit_syn) st<=6;   // send bit 2
    6  :      if (bit_syn) st<=7;   // send bit 3
    7  :      if (bit_syn) st<=8;   // send bit 4
    8  :      if (bit_syn) st<=9;   // send bit 5
    9  :      if (bit_syn) st<=10;  // send bit 6
    10 :      if (bit_syn) st<=11;  // send bit 7
    11 :      if (bit_syn) st<=12;  // parity 
    12 :      if (bit_syn) st<=13;  // stop bit 1
    13 :      if (bit_syn) st<=14;  // stop bit 2
    14 :      if (bit_syn) st<=15;  // stop bit 3
    15 :      if (bit_syn) st<=0;  
    default st<=0;  
    endcase
    
     
    always@ (posedge clk)if (~nrst)rdy<=1; else case (st )0: rdy <=1;default rdy<=0;endcase 
    
    always@ (posedge clk)if (~nrst)tx<=1; else case (st) 
    0,1  : tx<=1;
    2  : tx<=0;
    3  : tx<=din_save[0];
    4  : tx<=din_save[1];
    5  : tx<=din_save[2];
    6  : tx<=din_save[3];
    7  : tx<=din_save[4];
    8  : tx<=din_save[5];
    9  : tx<=din_save[6];
    10 : tx<=din_save[7];
    11 : 
    begin 
    case (parity_type)0:tx <=1;
    1:tx <= ~ if_byte_is_odd ;//odd
    2:tx <=  if_byte_is_odd ;// even
    default  tx <= 1;
    endcase  
    end 
    12,13,14,15 : tx<=1;
    default tx<=1;endcase 	 
    
    
    endmodule
    
    
    
    
    
    module uart_tx_tb  ;
    reg clk =0;
    reg nrst=0;
    reg wr=0;
    reg[1:0]  parity_type = 0;
    wire rdy ,tx ;
    reg [7:0] din = 8'haa ;
    
    always #5  clk = ~clk  ;
    
    initial begin
    #100 ; nrst = 1 ; 
    #100 ; 
    @(posedge clk);wr = 1;
    @(posedge clk);wr = 0;
    end 
    
     
     uart_tx #(   .BAUDRATE(115200),    .FREQ(100000000))  I_uart_tx (
        .clk(clk), 
    	.nrst(nrst),
        .wr(wr),
        .din(din),
        .tx(tx),
        .rdy(rdy),
        .parity_type( 0 )
        );
    
    endmodule
    
    
    
    
    
    

猜你喜欢

转载自blog.csdn.net/weixin_40640020/article/details/92377768
今日推荐