• FPGA实现串口接收


    功能实现:所有的疑惑都在注释中有解释!

    `timescale 1ns / 1ps
    //////////////////////////////////////////////////////////////////////////////////
    // Company: 
    // Engineer: 
    // 
    // Create Date:    14:26:20 01/04/2022 
    // Design Name: 
    // Module Name:    uart_rx_01 
    // Project Name: 
    // Target Devices: 
    // Tool versions: 
    // Description: 
    //
    // Dependencies: 
    //
    // Revision: 
    // Revision 0.01 - File Created
    // Additional Comments: 
    //
    //////////////////////////////////////////////////////////////////////////////////
    
    
    
    //设计思想如下:
    //传输的数据里面包含:一个起始位,八个数据位,一个停止位
    //每一个传输位:分为十六个采集数据点,每个数据采集点在其片段的中点位置,十六位中取其中七位为有效采集数据位前五后四不取,将其中七位数据位进行计算得出来该位为高还是低
    
    module uart_rx_01(
        clk,
        Reset_n,
        uart_rx,
        Bund_set,
        Data,
        Rx_Done
        );
         
         
        input clk;
        input Reset_n;
        input uart_rx;
        input [2:0]Bund_set;
        
        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[0] == 1)) //与下面的功能类似
        assign pedge_uart_rx = (uart_rx_r == 2'b01);
        
        wire nedge_uart_rx;//下降沿
        assign nedge_uart_rx = (uart_rx_r == 2'b10);
        
        //下降沿作为分频计数的开始
        reg RX_EN;
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)
            RX_EN <= 0;
        else if(nedge_uart_rx) //一开始理解有问题,觉得其他的数据中可能存在下降沿会影响RX_EN的使能,多虑了。只需要控制好RX_EN置为0的条件就ok
            RX_EN <= 1;
        else if(Rx_Done || (sta_bit >= 4)) //数据发送结束或者(起始位传输不对,错误的起始位)
            RX_EN <= 0;
            
        //基本的分频计数器
        reg [8:0] div_cnt;
        
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)
            div_cnt <= 0;
        else if(RX_EN)begin
            if(div_cnt == bund_dr - 1)
                div_cnt <= 0;
            else
                div_cnt <= div_cnt + 1'b1;
        end
        else
            div_cnt <= 0;
        
        //波特率转换为计数值门限
        reg [8:0] bund_dr;    
        always@(*)
            //1000000000为一秒钟, 16是将每个数据分为16个采集点, 20为每个时钟周期为20ns
            case(Bund_set)
            0: bund_dr <= 1000000000/16/20/9600;
            1: bund_dr <= 1000000000/16/20/19200;
            2: bund_dr <= 1000000000/16/20/38400;
            3: bund_dr <= 1000000000/16/20/57600;
            4: bund_dr <= 1000000000/16/20/115200;
            default: bund_dr <= 1000000000/16/20/9600;
            endcase
            
            
        //每次什么时候进行采集样本,发出一个上升沿信号
        wire bps_clk_16x;
        assign bps_clk_16x = (div_cnt == (bund_dr - 1) /2);
        
        //二级计数器,计数采集样本的总次数(十个数据需要总共160次)
        reg[7:0] bps_cnt;
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)
            bps_cnt <= 0;
        else if(RX_EN)begin
            if(bps_clk_16x)begin
                if(bps_cnt == 160)
                    bps_cnt <= 0;
                else
                    bps_cnt <= bps_cnt + 1'b1;
            end
            else
                bps_cnt <= bps_cnt;
        end
        else
            bps_cnt <= 0;
        
        reg [3:0]data_r[7:0];
        reg [3:0]sta_bit;
        reg [3:0]sto_bit;
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)begin    
            sta_bit <= 0;
            data_r[0] <= 0;
            data_r[1] <= 0;
            data_r[2] <= 0;
            data_r[3] <= 0;
            data_r[4] <= 0;
            data_r[5] <= 0;
            data_r[6] <= 0;
            data_r[7] <= 0;    
            sto_bit <= 0;
        end
        else if(bps_clk_16x)begin
            case(bps_cnt)
            0:begin
            sta_bit <= 0;
            data_r[0] <= 0;
            data_r[1] <= 0;
            data_r[2] <= 0;
            data_r[3] <= 0;
            data_r[4] <= 0;
            data_r[5] <= 0;
            data_r[6] <= 0;
            data_r[7] <= 0;    
            sto_bit <= 0;
            end
            5,6,7,8,9,10,11: sta_bit <= sta_bit + uart_rx;
            21,22,23,24,25,26,27:data_r[0] <= data_r[0] + uart_rx;
            37,38,39,40,41,42,43:data_r[1] <= data_r[1] + uart_rx;
            53,54,55,56,57,58,59:data_r[2] <= data_r[2] + uart_rx;
            69,70,71,72,73,74,75:data_r[3] <= data_r[3] + uart_rx;
            85,86,87,88,89,90,91:data_r[4] <= data_r[4] + uart_rx;
            101,102,103,104,105,106,107:data_r[5] <= data_r[5] + uart_rx;
            117,118,119,120,121,122,123:data_r[6] <= data_r[6] + uart_rx;
            133,134,135,136,137,138,139:data_r[7] <= data_r[7] + uart_rx;
            149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;
            default:;
            endcase
            end
            
            //将数据输出到Data上,进行判断,判断其七次累加的结果
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)
            Data <= 0;
        else if(bps_clk_16x && (bps_cnt == 160))begin
            Data[0] <= (data_r[0] >= 4)? 1'b1:1'b0;
            Data[1] <= (data_r[1] >= 4)? 1'b1:1'b0;
            Data[2] <= (data_r[2] >= 4)? 1'b1:1'b0;
            Data[3] <= (data_r[3] >= 4)? 1'b1:1'b0;
            Data[4] <= (data_r[4] >= 4)? 1'b1:1'b0;
            Data[5] <= (data_r[5] >= 4)? 1'b1:1'b0;
            Data[6] <= (data_r[6] >= 4)? 1'b1:1'b0;
            Data[7] <= (data_r[7] >= 4)? 1'b1:1'b0;
        
        end
        
        //Rx_Done信号的处理
        always@(posedge clk or negedge Reset_n)
        if(!Reset_n)
            Rx_Done <= 0;
        else if((div_cnt == (bund_dr - 1)/2) && (bps_cnt == 160))
            Rx_Done <= 1;
        else
            Rx_Done <= 0;
        
    endmodule

    测试激励

    `timescale 1ns / 1ps
    
    ////////////////////////////////////////////////////////////////////////////////
    // Company: 
    // Engineer:
    //
    // Create Date:   21:30:47 01/05/2022
    // Design Name:   uart_rx_01
    // Module Name:   E:/FPGA_WORKSPACE/uart_rx/uart_rx_01_test.v
    // Project Name:  uart_rx
    // Target Device:  
    // Tool versions:  
    // Description: 
    //
    // Verilog Test Fixture created by ISE for module: uart_rx_01
    //
    // Dependencies:
    // 
    // Revision:
    // Revision 0.01 - File Created
    // Additional Comments:
    // 
    ////////////////////////////////////////////////////////////////////////////////
    
    module uart_rx_01_test;
    
        // Inputs
        reg clk;
        reg Reset_n;
        reg uart_rx;
        wire [2:0] Bund_set;
    
        // Outputs
        wire [7:0] Data;
        wire Rx_Done;
    
        assign Bund_set = 4;
        // Instantiate the Unit Under Test (UUT)
        uart_rx_01 uut (
            .clk(clk), 
            .Reset_n(Reset_n), 
            .uart_rx(uart_rx), 
            .Bund_set(Bund_set), 
            .Data(Data), 
            .Rx_Done(Rx_Done)
        );
        initial clk = 1;
        always #10 clk = !clk;
        
        initial begin
            // Initialize Inputs
            Reset_n = 0;
            uart_rx = 0;
    
            // Wait 100 ns for global reset to finish
            #201;
            Reset_n = 1;
            #200;
            uart_tx_data(8'h5a);
            @(posedge Rx_Done);
            #5000;
            uart_tx_data(8'ha5);
            @(posedge Rx_Done);
            #5000;
            uart_tx_data(8'h56);
            @(posedge Rx_Done);
            #5000;
            
            // Add stimulus here
    
        end
        task uart_tx_data;
            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;
                #8000;
            end
        endtask
          
    endmodule

    `timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company: // Engineer: // // Create Date:    14:26:20 01/04/2022 // Design Name: // Module Name:    uart_rx_01 // Project Name: // Target Devices: // Tool versions: // Description: //// Dependencies: //// Revision: // Revision 0.01 - File Created// Additional Comments: ////////////////////////////////////////////////////////////////////////////////////


    //设计思想如下://传输的数据里面包含:一个起始位,八个数据位,一个停止位//每一个传输位:分为十六个采集数据点,每个数据采集点在其片段的中点位置,十六位中取其中七位为有效采集数据位前五后四不取,将其中七位数据位进行计算得出来该位为高还是低
    module uart_rx_01(clk,Reset_n,uart_rx,Bund_set,Data,Rx_Done    );  input clk;input Reset_n;input uart_rx;input [2:0]Bund_set;output reg [7:0]Data;output reg Rx_Done;reg [1:0] uart_rx_r;always@(posedge clk)beginuart_rx_r[0] <= uart_rx;uart_rx_r[1] <= uart_rx_r[0];endwire pedge_uart_rx;//上升沿//assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1)) //与下面的功能类似assign pedge_uart_rx = (uart_rx_r == 2'b01);wire nedge_uart_rx;//下降沿assign nedge_uart_rx = (uart_rx_r == 2'b10);//下降沿作为分频计数的开始reg RX_EN;always@(posedge clk or negedge Reset_n)if(!Reset_n)RX_EN <= 0;else if(nedge_uart_rx) //一开始理解有问题,觉得其他的数据中可能存在下降沿会影响RX_EN的使能,多虑了。只需要控制好RX_EN置为0的条件就okRX_EN <= 1;else if(Rx_Done || (sta_bit >= 4)) //数据发送结束或者(起始位传输不对,错误的起始位)RX_EN <= 0;//基本的分频计数器reg [8:0] div_cnt;always@(posedge clk or negedge Reset_n)if(!Reset_n)div_cnt <= 0;else if(RX_EN)beginif(div_cnt == bund_dr - 1)div_cnt <= 0;elsediv_cnt <= div_cnt + 1'b1;endelsediv_cnt <= 0;//波特率转换为计数值门限reg [8:0] bund_dr;always@(*)    //1000000000为一秒钟, 16是将每个数据分为16个采集点, 20为每个时钟周期为20nscase(Bund_set)0: bund_dr <= 1000000000/16/20/9600;1: bund_dr <= 1000000000/16/20/19200;2: bund_dr <= 1000000000/16/20/38400;3: bund_dr <= 1000000000/16/20/57600;4: bund_dr <= 1000000000/16/20/115200;default: bund_dr <= 1000000000/16/20/9600;endcase//每次什么时候进行采集样本,发出一个上升沿信号wire bps_clk_16x;assign bps_clk_16x = (div_cnt == (bund_dr - 1) /2);//二级计数器,计数采集样本的总次数(十个数据需要总共160次)reg[7:0] bps_cnt;always@(posedge clk or negedge Reset_n)if(!Reset_n)bps_cnt <= 0;else if(RX_EN)beginif(bps_clk_16x)beginif(bps_cnt == 160)bps_cnt <= 0;elsebps_cnt <= bps_cnt + 1'b1;endelsebps_cnt <= bps_cnt;endelsebps_cnt <= 0;reg [3:0]data_r[7:0];reg [3:0]sta_bit;reg [3:0]sto_bit;always@(posedge clk or negedge Reset_n)if(!Reset_n)beginsta_bit <= 0;data_r[0] <= 0;data_r[1] <= 0;data_r[2] <= 0;data_r[3] <= 0;data_r[4] <= 0;data_r[5] <= 0;data_r[6] <= 0;data_r[7] <= 0;sto_bit <= 0;endelse if(bps_clk_16x)begincase(bps_cnt)0:beginsta_bit <= 0;data_r[0] <= 0;data_r[1] <= 0;data_r[2] <= 0;data_r[3] <= 0;data_r[4] <= 0;data_r[5] <= 0;data_r[6] <= 0;data_r[7] <= 0;sto_bit <= 0;end5,6,7,8,9,10,11: sta_bit <= sta_bit + uart_rx;21,22,23,24,25,26,27:data_r[0] <= data_r[0] + uart_rx;37,38,39,40,41,42,43:data_r[1] <= data_r[1] + uart_rx;53,54,55,56,57,58,59:data_r[2] <= data_r[2] + uart_rx;69,70,71,72,73,74,75:data_r[3] <= data_r[3] + uart_rx;85,86,87,88,89,90,91:data_r[4] <= data_r[4] + uart_rx;101,102,103,104,105,106,107:data_r[5] <= data_r[5] + uart_rx;117,118,119,120,121,122,123:data_r[6] <= data_r[6] + uart_rx;133,134,135,136,137,138,139:data_r[7] <= data_r[7] + uart_rx;149,150,151,152,153,154,155: sto_bit <= sto_bit + uart_rx;default:;endcaseend//将数据输出到Data上,进行判断,判断其七次累加的结果always@(posedge clk or negedge Reset_n)if(!Reset_n)Data <= 0;else if(bps_clk_16x && (bps_cnt == 160))beginData[0] <= (data_r[0] >= 4)? 1'b1:1'b0;Data[1] <= (data_r[1] >= 4)? 1'b1:1'b0;Data[2] <= (data_r[2] >= 4)? 1'b1:1'b0;Data[3] <= (data_r[3] >= 4)? 1'b1:1'b0;Data[4] <= (data_r[4] >= 4)? 1'b1:1'b0;Data[5] <= (data_r[5] >= 4)? 1'b1:1'b0;Data[6] <= (data_r[6] >= 4)? 1'b1:1'b0;Data[7] <= (data_r[7] >= 4)? 1'b1:1'b0;end//Rx_Done信号的处理always@(posedge clk or negedge Reset_n)if(!Reset_n)Rx_Done <= 0;else if((div_cnt == (bund_dr - 1)/2) && (bps_cnt == 160))Rx_Done <= 1;elseRx_Done <= 0;endmodule

  • 相关阅读:
    BestCoder Round #32
    USACO Runaround Numbers
    USACO Subset Sums
    USACO Sorting a Three-Valued Sequence
    USACO Ordered Fractions
    USACO 2.1 The Castle
    Codeforces Round #252 (Div. 2)
    Codeforces Round #292 (Div. 2)
    BZOJ 1604: [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居
    BZOJ 1603: [Usaco2008 Oct]打谷机
  • 原文地址:https://www.cnblogs.com/qkqBeer/p/15771174.html
Copyright © 2020-2023  润新知