Bootstrap

35.UART(通用异步收发传输器)-RS232(2)

(1)RS232接收模块visio框图:

(2)接收模块Verilog代码编写:

/*
常见波特率: 4800、9600、14400、115200
在系统时钟为50MHz时,对应计数为:   
(1/4800)    * 10^9 /20 -1 = 10416     
(1/9600)    * 10^9 /20 -1 = 5207
(1/14400)   * 10^9 /20 -1 = 3471
(1/115200)  * 10^9 /20 -1 = 433 
*/

module rs232_rx
(
    input [16:0]    baud_set    ,
    input           clk         ,
    input           reset_n     ,
    input           rx          ,
    input           rx_start    ,
    
    output reg[7:0] rx_data     ,
    output reg      rx_done     
    
);
    
    reg [15:0]      BAUD_MCNT   ;
    reg             rx_reg0     ;
    reg             rx_reg1     ;
    reg             rx_reg2     ;
    reg             en_baud_cnt ;
    reg [15:0]      baud_cnt    ;
    reg [3:0]       bit_cnt     ;
    reg [7:0]       r_rx_data   ;
    
    wire            nedge       ;
    wire            w_rx_done   ;
    
//波特最大计数设计
    always@(posedge clk)
        begin
            case(baud_set)
                17'd4800    :BAUD_MCNT <= 16'd10416;
                17'd9600    :BAUD_MCNT <= 16'd5207;
                17'd14400   :BAUD_MCNT <= 16'd3471;
                17'd115200  :BAUD_MCNT <= 16'd433;
                default     :BAUD_MCNT <= 16'd5207;      //当输入baud_set为其他值时,一律当成9600处理。
            endcase
        end
    
//输入信号打拍处理
    always@(posedge clk)
        begin
            rx_reg0 <= rx;
            rx_reg1 <= rx_reg0;
        end

//下降沿设计
    always@(posedge clk)
        rx_reg2 <= rx_reg1;
        
    assign nedge = (rx_reg2) && (!rx_reg1);
    
//波特率计数使能信号设计 
   always@(posedge clk or negedge reset_n)
        if(!reset_n)
            en_baud_cnt <= 1'd0;
        else if(!rx_start)
            en_baud_cnt <= 1'd0;
        else if(nedge)
            en_baud_cnt <= 1'd1;
        else if((bit_cnt == 4'd0) && (baud_cnt == BAUD_MCNT/2)&&(rx_reg2))      //防止起始位只是一个抖动
            en_baud_cnt <= 1'd0;
        else if((bit_cnt == 4'd9) && (baud_cnt == BAUD_MCNT/2))
            en_baud_cnt <= 1'd1;
        else    
            en_baud_cnt <= en_baud_cnt;
            
//波特计数器模块设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            baud_cnt <= 16'd0;
        else if(!en_baud_cnt)
            baud_cnt <= 16'd0;
        else if(baud_cnt == BAUD_MCNT)
            baud_cnt <= 16'd0;
        else 
            baud_cnt <= baud_cnt + 16'd1;
            
//位计数器模块设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            bit_cnt <= 4'd0;
        else if((baud_cnt == BAUD_MCNT) &&(bit_cnt == 4'd9))
            bit_cnt <= 4'd0;
        else if(baud_cnt == BAUD_MCNT)
            bit_cnt <= bit_cnt + 4'd1;
        else 
            bit_cnt <= bit_cnt;
            
//rx_data设计
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            r_rx_data <= 8'd0;
        else if(baud_cnt == BAUD_MCNT/2)begin
            case(bit_cnt)
                4'd1: r_rx_data[0] <= rx_reg2;
                4'd2: r_rx_data[1] <= rx_reg2;
                4'd3: r_rx_data[2] <= rx_reg2;
                4'd4: r_rx_data[3] <= rx_reg2;
                4'd5: r_rx_data[4] <= rx_reg2;
                4'd6: r_rx_data[5] <= rx_reg2;
                4'd7: r_rx_data[6] <= rx_reg2;
                4'd8: r_rx_data[7] <= rx_reg2;
                default:r_rx_data <= r_rx_data;
            endcase
        end
        else 
            r_rx_data <= r_rx_data;
    
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            rx_data <= 8'd0;
        else if(w_rx_done)
            rx_data <= r_rx_data;
        else    
            rx_data <= rx_data;
    
//w_rx_done和rx_done信号设计
    assign w_rx_done = (bit_cnt == 4'd9) && (baud_cnt == BAUD_MCNT/2) ;
    
    always@(posedge clk or negedge reset_n)
        if(!reset_n)
            rx_done <= 1'd0;
        else 
            rx_done <= w_rx_done;
            
endmodule

(3)仿真文件代码:

`timescale 1ns / 1ps

module rs232_tx_tb;

reg   [16:0]        baud_set    ;
reg                 clk         ;
reg                 reset_n     ;
reg                 rx          ;
reg                 rx_start    ;

wire [7:0]          rx_data     ;
wire                rx_done     ;

    initial clk = 1'd1;
    always #10 clk = ~clk;
    
    initial begin 
        baud_set <= 17'd9600;
        rx_start <= 1'd0;
        #200;
        rx_start <= 1'd1;
        reset_n <= 1'd0;
        rx      <= 1'd1;
        #15;
        reset_n <= 1'd1;
        @(posedge clk)
        set_bit(8'd1 );
        set_bit(8'd3 );
        set_bit(8'd7 );
        set_bit(8'd15);
        $stop;
    end


rs232_rx    rs232_rx_inst
(
    .baud_set    ( baud_set )     ,
    .clk         ( clk      )     ,
    .reset_n     ( reset_n  )     ,
    .rx          ( rx       )     ,
    .rx_start    ( rx_start )     ,

    .rx_data     ( rx_data  )     ,
    .rx_done     ( rx_done  )     
    
);

task   set_bit(
    input [7:0]data
);

integer i;
    for(i=0;i<10;i=i+1)begin
        case(i)
            0: rx <= 1'd0;
            1: rx <= data[0];
            2: rx <= data[1];
            3: rx <= data[2];
            4: rx <= data[3];
            5: rx <= data[4];
            6: rx <= data[5];
            7: rx <= data[6];
            8: rx <= data[7];
            9: rx <= 1'd1;
        endcase
        #(5208 * 20);        
    end
endtask


endmodule

(4)仿真波形:

;