FPGA——异步串行通信(UART)接收

Posted cnlntr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FPGA——异步串行通信(UART)接收相关的知识,希望对你有一定的参考价值。

程序代码:

module uart_byte_rx(
    clk         ,//50MHz时钟
    rst_n       ,//复位
    baud_set    ,//波特率设置
    rs232_rx    ,//rs232数据接收
    data_byte   ,//并行数据输出
    rx_done      //单个字节接收完标志
    );

    //参数定义s
    parameter           DATA_W =            8;
    parameter           BAUS_W =            3;
    parameter           DABS_W =            3;
    parameter           BAUV_W =           13;
    parameter           CNTB_W =            8;
    parameter           RDAB_W =            3;
    parameter           RDAB_N =            8;

    //输入信号定义
    input               clk         ;
    input               rst_n       ;
    input [BAUS_W-1:0]  baud_set    ;
    input               rs232_rx    ;

    //输出信号定义
    output[DATA_W-1:0]  data_byte   ;
    output              rx_done     ;

    //输出信号定义
    reg   [DATA_W-1:0]  data_byte   ;
    wire                rx_done     ;
    //中间信号定义
    reg                 uart_state  ;//串口接收状态

    reg   [DABS_W-1:0]  data_byt_syn;
    wire                nedge       ;

    reg   [BAUV_W-1:0]  baud_div    ;//波特率分频值

    reg   [BAUV_W-1:0]  cnt_div     ;//分频计数器
    wire                add_cnt_div ;
    wire                end_cnt_div ;

    reg   [CNTB_W-1:0]  cnt_byt     ;
    wire                add_cnt_byt ;
    wire                end_cnt_byt ;

    reg   [RDAB_W-1:0]  start_bit   ;
    reg   [RDAB_W-1:0]  stop_bit    ;

    reg   [RDAB_W-1:0]  r_data_byte[RDAB_N-1:0];//RDAB_N寄存器,每个寄存器位宽为RDAB_W

    //接入两个D触发器,对异步数据进行同步化处理
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            data_byt_syn <= 0;
        end
        else begin
            data_byt_syn <= {data_byt_syn[1:0],rs232_rx};
        end
    end

    assign nedge = (data_byt_syn[2:1== 2‘b10);

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1‘b0)begin
            uart_state <= 0;
        end
        else if(nedge) begin
            uart_state <= 1;//检测到起始位0
        end
        else if(end_cnt_byt)begin
            uart_state <= 0;
        end
    end

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1‘b0)begin
            baud_div <= 0;
        end
        else begin
            //取16个采样点
            case (baud_set)
                0 : baud_div <=  13‘d5208;//600bps/16
                1 : baud_div <=  13‘d2604;//1200bps/16
                2 : baud_div <=  13‘d1302;//2400bps/16
                3 : baud_div <=  13‘d651 ;//4800bps/16
                4 : baud_div <=  13‘d325 ;//9600bps/16
                5 : baud_div <=  13‘d163 ;//19200bps/16
                6 : baud_div <=  13‘d81  ;//38400bps/16
                7 : baud_div <=  13‘d54  ;//57600bps/16
                default
                    baud_div <= 0;
            endcase
        end
    end

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_div <= 0;
        end
        else if(add_cnt_div)begin
            if(end_cnt_div)
                cnt_div <= 0;
            else
                cnt_div <= cnt_div + 1‘b1;
            end
    end
    assign add_cnt_div = (uart_state == 1);
    assign end_cnt_div = add_cnt_div && cnt_div == baud_div-1 ;

    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_byt <= 0;
        end
        else if(add_cnt_byt)begin
            if(end_cnt_byt)
                cnt_byt <= 0;
            else
                cnt_byt <= cnt_byt + 1‘b1;
            end
    end
    assign add_cnt_byt = (end_cnt_div == 1);
    assign end_cnt_byt = (add_cnt_byt && cnt_byt == 160-1|| (start_bit > 2);//10个比特,每个比特采样16个点

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1‘b0)begin
            start_bit <= 0;
            r_data_byte[0<= 0;
            r_data_byte[1<= 0;
            r_data_byte[2<= 0;
            r_data_byte[3<= 0;
            r_data_byte[4<= 0;
            r_data_byte[5<= 0;
            r_data_byte[6<= 0;
            r_data_byte[7<= 0;
            stop_bit <= 0;
        end
        else if(uart_state) begin
            case (cnt_byt)
                //在16个点中,取样中间6个点
                5,6,7,8,9,10            : start_bit <= start_bit + rs232_rx;

                21,22,23,24,25,26       : r_data_byte[0<= r_data_byte[0+ rs232_rx;
                37,38,39,40,41,42       : r_data_byte[1<= r_data_byte[1+ rs232_rx;
                53,54,55,56,57,58       : r_data_byte[2<= r_data_byte[2+ rs232_rx;
                69,70,71,72,73,74       : r_data_byte[3<= r_data_byte[3+ rs232_rx;
                85,86,87,88,89,90       : r_data_byte[4<= r_data_byte[4+ rs232_rx;

                101,102,103,104,105,106 : r_data_byte[5<= r_data_byte[5+ rs232_rx;
                117,118,119,120,121,122 : r_data_byte[6<= r_data_byte[6+ rs232_rx;
                133,134,135,136,137,138 : r_data_byte[7<= r_data_byte[7+ rs232_rx;
                149,150,151,152,153,154 : stop_bit <= stop_bit + rs232_rx;
                defaultbegin
                    start_bit <= start_bit;
                    r_data_byte[0<= r_data_byte[0];
                    r_data_byte[1<= r_data_byte[1];
                    r_data_byte[2<= r_data_byte[2];
                    r_data_byte[3<= r_data_byte[3];
                    r_data_byte[4<= r_data_byte[4];
                    r_data_byte[5<= r_data_byte[5];
                    r_data_byte[6<= r_data_byte[6];
                    r_data_byte[7<= r_data_byte[7];
                    stop_bit <= stop_bit;
                end
            endcase
        end
        else begin
            start_bit <= 0;
            r_data_byte[0<= 0;
            r_data_byte[1<= 0;
            r_data_byte[2<= 0;
            r_data_byte[3<= 0;
            r_data_byte[4<= 0;
            r_data_byte[5<= 0;
            r_data_byte[6<= 0;
            r_data_byte[7<= 0;
            stop_bit <= 0;
        end
    end

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1‘b0)begin
            data_byte <= 0;
        end
        else if(end_cnt_byt)begin
            //取r_data_byte的最高位,当r_data_byte[n]中取样‘1‘的个数大于或等于4时,该比特位为1,否则为0
            data_byte[0<= r_data_byte[0][2];
            data_byte[1<= r_data_byte[1][2];
            data_byte[2<= r_data_byte[2][2];
            data_byte[3<= r_data_byte[3][2];
            data_byte[4<= r_data_byte[4][2];
            data_byte[5<= r_data_byte[5][2];
            data_byte[6<= r_data_byte[6][2];
            data_byte[7<= r_data_byte[7][2];
        end
    end

    assign rx_done = (add_cnt_byt && cnt_byt == 160 - 1);

endmodule

验证代码:

module uart_rx_top(
    clk     ,
    rst_n   ,
    rs232_rx,
    //其他信号,举例led
    led
    );

    //参数定义
    parameter           LED_W =             4;
    parameter           DAB_W =             8;

    //输入信号定义
    input               clk         ;
    input               rst_n       ;
    input               rs232_rx    ;

    //输出信号定义
    output[LED_W-1:0]   led         ;

    //输出信号reg定义
    wire  [LED_W-1:0]   led         ;

    //中间信号定义
    wire  [DAB_W-1:0]   data_byte   ;
    //组合逻辑写法
    assign led = data_byte[7:4];

    uart_byte_rx uart_byte_rx(
    .clk(clk)               ,//50MHz时钟
    .rst_n(rst_n)           ,//复位
    .baud_set(3‘d7)         ,//波特率设置
    .rs232_rx(rs232_rx)     ,//rs232数据接收
    .data_byte(data_byte)   ,//并行数据输出
    .rx_done()               //单个字节接收完标志
    );

endmodule

仿真代码:

技术图片
`timescale 1 ns/ 1 ps
module uart_rx_top_vlg_tst();
reg clk;
reg rs232_rx;
reg rst_n;
// wires                                               
wire [3:0]  led;
                      
uart_rx_top i1 (
    .clk(clk),
    .led(led),
    .rs232_rx(rs232_rx),
    .rst_n(rst_n)
);
initial begin                                                                                       
    clk = 0;
end 
                                                   
always begin                                                  
   #1 clk = ~clk;
end

initial begin                                                                                       
    rst_n = 0;
    #10;
    rst_n = 1;
end 

initial begin
    rs232_rx = 1b1;
    #20;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b0;

    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
    
    #100;
    ///////////////////
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b0;

    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b1;
    
    #1728;
    rs232_rx = 1b0;
    
    #1728;
    rs232_rx = 1b1;
end 
                                  
endmodule
View Code

 

以上是关于FPGA——异步串行通信(UART)接收的主要内容,如果未能解决你的问题,请参考以下文章

EDA课设 FPGA开发板 VHDL实现串口通信

EDA课设 FPGA开发板 VHDL实现串口通信

计算机与 BASYS 3 FPGA 之间的 UART 通信

DSP之通信之异步串口

UART

FPGA 串口通信