FPGA串口接收

本文详细解释了UART串口接收的工作原理,包括数据采样、高低电平统计、起始位检测以及如何根据不同的波特率调整计数器。通过实例展示了如何实现基于边沿检测的串口数据接收过程。
摘要由CSDN通过智能技术生成

// 串口接收原理:
// 基本原理:采样
// 思路:一位数据采样多次,统计高低电平出现的次数,次数多的为该位的电平值
//      例:采样7次,每次的结果相加,最终的结果:0、1、2、3为低电平,4、5、6、7为高电平
//      将一个数据分为16段,舍弃前5段和后4段,取中间7段进行采样
// 起始位检测:通过边沿检测电路

// Create Date: 2024/04/05 13:44:12
// Design Name: hilary
// Module Name: uart_byte_rx
// 串口接收原理:
// 基本原理:采样
// 思路:一位数据采样多次,统计高低电平出现的次数,次数多的为该位的电平值
//      例:采样7次,每次的结果相加,最终的结果:0、1、2、3为低电平,4、5、6、7为高电平
//      将一个数据分为16段,舍弃前5段和后4段,取中间7段进行采样
// 起始位检测:通过边沿检测电路
// 波特率设为:9600
// 计数器:1000000000/9600/16/20 = 325
// 计数325产生一个bps_clk

// 波特率设为:115200
// 计数器:1000000000/115200/16/20 = 27
// 计数27产生一个bps_clk

// 波特率设为:9600
// 计数器:1000000000/9600/16/20 = 325
// 计数325产生一个bps_clk

// 波特率设为:115200
// 计数器:1000000000/115200/16/20 = 27
// 计数27产生一个bps_clk


module uart_byte_rx(
    Clk,
    Reset_n,
    Baud_Set,
    uart_rx,
    Data,
    Rx_Done);

    input Clk;
    input Reset_n;
    input [2:0] Baud_Set;
    input uart_rx;
    output reg [7:0] Data;
    output reg Rx_Done;

    //边沿检测
    reg [1:0] uart_rx_r;
    always @(posedge Clk) begin
        uart_rx_r[0] <= uart_rx;
        uart_rx_r[1] <= uart_rx_r[0];  
    end

    wire pedge_uart_rx;
    // assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[1] == 1));
    assign pedge_uart_rx = (uart_rx_r == 2 'b01);

    wire nedge_uart_rx;
    // assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[1] == 1));
    assign nedge_uart_rx = (uart_rx_r == 2 'b10);

    // 波特率设置
    reg [8:0] Bps_DR;
    always@(*)
        case (Baud_Set)
            0 : Bps_DR = 1000000000/9600/16/20 - 1;
            1 : Bps_DR = 1000000000/19200/16/20 - 1;
            2 : Bps_DR = 1000000000/38400/16/20 - 1;
            3 : Bps_DR = 1000000000/57600/16/20 - 1;
            4 : Bps_DR = 1000000000/115200/16/20 - 1;
            default: Bps_DR = 1000000000/9600/16/20 - 1;
        endcase

    wire bps_clk_16x;
    assign bps_clk_16x = (div_cnt == Bps_DR / 2);
    reg [8:0] div_cnt;

    //使能电平计数信号
    reg RX_EN;
    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            RX_EN <= 0;
        end
        else if (nedge_uart_rx) begin
            RX_EN <= 1;
        end
        else if (Rx_Done || (sta_bit >=  4)) begin
            RX_EN <= 0;
        end  
    end  

    //分频计数器
    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            div_cnt <= 0;
        end
        else if (RX_EN) begin
            if (div_cnt == Bps_DR) begin
                div_cnt <= 0;
            end
            else
                div_cnt <= div_cnt  + 1 'b1;
        end
        else
            div_cnt <= 0; 
    end

    reg [7:0] bps_cnt ;
    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            bps_cnt <= 0;
        end
        else if (RX_EN) begin
                     if (bps_clk_16x) begin
                            if (bps_cnt == 160) begin
                                bps_cnt<= 0;
                            end
                            else 
                                bps_cnt <= bps_cnt + 1 'b1;
                    end
                
                     else
                         bps_cnt <= bps_cnt;
                end
                else
                     bps_cnt <= 0;
    end
    

    //接收数据
    // reg width name number 二维寄存器
    // reg 位宽 名字 数量
    reg [2:0] r_data[7:0];
    reg [2:0] sta_bit;
    reg [2:0] sto_bit;

    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            sta_bit <= 0;
            sto_bit <= 0;

            r_data[0] <= 0;
            r_data[1] <= 0;
            r_data[2] <= 0;
            r_data[3] <= 0;

            r_data[4] <= 0;
            r_data[5] <= 0;
            r_data[6] <= 0;
            r_data[7] <= 0;
        end
        else if(bps_clk_16x) begin
            case (bps_cnt)
                0 : begin
                        sta_bit <= 0;
                        sto_bit <= 0;

                        r_data[0] <= 0;
                        r_data[1] <= 0;
                        r_data[2] <= 0;
                        r_data[3] <= 0;

                        r_data[4] <= 0;
                        r_data[5] <= 0;
                        r_data[6] <= 0;
                        r_data[7] <= 0;
                    end
                5,6,7,8,9,10,11 : sta_bit <= sta_bit + uart_rx; 
                21,22,23,24,25,26,27 : r_data[0] <= r_data[0] + uart_rx;
                37,38,39,40,41,42,43 : r_data[1] <= r_data[1] + uart_rx;
                53,54,55,56,57,58,59 : r_data[2] <= r_data[2] + uart_rx;
                69,70,71,72,73,74,75 : r_data[3] <= r_data[3] + uart_rx;
                
                85,86,87,88,89,90,91 : r_data[4] <= r_data[4] + uart_rx;
                101,102,103,104,105,106,107 : r_data[5] <= r_data[5] + uart_rx;
                117,118,119,120,121,122,123 : r_data[6] <= r_data[6] + uart_rx;
                133,134,135,136,137,138,139 : r_data[7] <= r_data[7] + uart_rx;
                
                149,150,151,152,153,154,155 : sto_bit <= sto_bit + uart_rx;
                default: ;
            endcase
        end
    end

    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            Data <= 0;
        end
        else if (bps_clk_16x && (bps_cnt == 159) ) begin
            Data[0] <= (r_data[0] >= 4)? 1 'b1:1 'b0;
            Data[1] <= (r_data[1] >= 4)? 1 'b1:1 'b0;
            Data[2] <= (r_data[2] >= 4)? 1 'b1:1 'b0;
            Data[3] <= (r_data[3] >= 4)? 1 'b1:1 'b0;

            Data[4] <= (r_data[4] >= 4)? 1 'b1:1 'b0;
            Data[5] <= (r_data[5] >= 4)? 1 'b1:1 'b0;
            Data[6] <= (r_data[6] >= 4)? 1 'b1:1 'b0;
            Data[7] <= (r_data[7] >= 4)? 1 'b1:1 'b0;
        end
    end

    
    always @(posedge Clk or negedge Reset_n) begin
        if (!Reset_n) begin
            Rx_Done <= 0;
        end
        else if ((div_cnt == Bps_DR/2) && (bps_cnt == 160))begin
            Rx_Done <= 1;
        end
        else
            Rx_Done <= 0;
     end
endmodule

仿真测试:

module uart_byte_re_tb();
    reg Clk;
    reg Reset_n;
    wire [2:0] Baud_Set;
    reg uart_rx;
    wire [7:0] Data;
    wire Rx_Done;

    assign Baud_Set = 4;

    uart_byte_rx uart_byte_rx(
        Clk,
        Reset_n,
        Baud_Set,
        uart_rx,
        Data,
        Rx_Done);


    initial Clk = 1;
    always#10 Clk = ~Clk;

    initial begin
        Reset_n <= 0;
        #201;
        Reset_n <= 1;
        #200;
        uart_tx_byte(8 'h5a);

        #90000;
        uart_tx_byte(8 'ha5);

        #90000;
        uart_tx_byte(8 'h86);

        #90000;        
        $stop;
    end    
    task uart_tx_byte;
        input [7:0] tx_data;
        begin
            uart_rx = 1;
            #20;
            uart_rx = 0;
            #8680;
            uart_rx = tx_data[0];
            #8680;
            uart_rx = tx_data[1];
            #8680;
            uart_rx = tx_data[2];
            #8680;
            uart_rx = tx_data[3];
            
            #8680;
            uart_rx = tx_data[4];
            #8680;
            uart_rx = tx_data[5];
            #8680;
            uart_rx = tx_data[6];
            #8680;
            uart_rx = tx_data[7];
            #8680;
            uart_rx = 1;
            #8680;
        end
        endtask
endmodule

结果:

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值