草庐IT

串口接收模块——verilog实现

FPGA与ZYNQ的学习笔记 2023-03-28 原文

1、设计想法

原理与之前的串口发送模块一样,1位的起始位和8位的数据位再加上1位的停止位。唯一不同的是在接收的时候要考虑到有干扰的情况下,为了避免干扰,我们对每位数据进行多次采样,按出现概率大的值为该数据位的值。

如果按照通常想法在每bits位中间取值的话,bit3位出现图中的干扰很有可能会读出错误的值。所以需要对每位进行多次抽样进行判断。

每位要抽8次的话,那需要将每个波特段分成9等分。

2、状态机设定

3、模块代码

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: Lclone
// 
// Create Date: 2022/12/16 15:37:44
// Design Name: uart_byte_rx
// Module Name: uart_byte_rx
// Project Name: uart_byte_rx
// Target Devices: 
// Tool Versions: 
// Description: 8位串口接收模块
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_byte_rx
  # (
        parameter   RX_BAUD  = 9600,            //波特率
        parameter   CLK_FQC  = 50_000_000,      //模块时钟频率
        parameter   BAUD_CNT = CLK_FQC/RX_BAUD) //模块每波特需要计数的次数(设置此端口方便仿真用)
    (
        input               Clk,                //时钟频率接口
        input               Rst_n,              //复位接口
        input               Uart_rx,            //串口接收接口
        output  reg  [7:0]  Data,               //接收到的数据接口
        output  reg         Rx_done             //接收完成信号
    );
    
    reg            uart_rx_r;                   //延一拍
    reg            uart_rx_rr;                  //延两拍
    reg            uart_rx_rrr;                 //延三拍,减少亚稳态出现的概率
    reg            receiv_begin;                //接收开始信号
    reg            receiv_flag;                 //接收状态信号
    reg   [ 3:0]   state;                       //状态机寄存器
    reg   [15:0]   baud_cnt;                    //波及计数器
    reg   [ 3:0]   sampel_cnt;                  //采样计数器
    reg            sampel_en;                   //采样使能
    reg            sampel_ref;                  //样本寄存器
    reg   [ 3:0]   acc;                         //累加寄存器
    reg   [ 3:0]   bit_cnt;                     //数据位寄存器
    
    always @(posedge Clk) begin   //延两拍为下降沿捕获
        uart_rx_r <= Uart_rx;
        uart_rx_rr <= uart_rx_r;
        uart_rx_rrr <= uart_rx_rr;
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //接收信号发生
        if(Rst_n == 0)
            receiv_begin <= 0;
        else if(state == 0 & uart_rx_rrr & ~uart_rx_rr)
            receiv_begin <= 1'b1;
        else
            receiv_begin <= 0;            
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //状态机
        if(Rst_n == 0) begin
            state <= 0;
            sampel_ref <= 8'b0;
            acc <= 8'b0;
            Data <= 8'b0;
        end
        else case(state)
            0:     //空闲状态
                if(receiv_begin == 1)
                    state <= 3'd1;
                else
                    state <= 0;
            
            1: begin	//抽样状态
                    if(sampel_en == 1) begin
                           sampel_ref <= Uart_rx;
                           state <= 3'd2;
                    end

                    else
                        state <= 3'b1;
               end   
                    
            2: begin    //数据判断状态

                    acc <= acc + sampel_ref;
                   
                    if(sampel_cnt == 7) begin
                        if(acc >= 4)
                            begin Data[7] <= 1'b1; state <= 3'd3;acc <= 8'b0; end
                        else
                            begin Data[7] <= 0; state <= 3'd3;acc <= 8'b0; end
                    end
                    
                    else
                        state <= 3'd1;
               end                            

            3: begin    //数据移位状态
                    if(bit_cnt < 8) begin
                        Data <= Data >> 1;
                        state <= 3'd1; 
                    end
                    
                    else 
                        state <= 0;
            end
            
            default:;
       endcase
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //接收进行标志 
        if(Rst_n == 0)
            receiv_flag <= 0;
        else if(receiv_begin == 1)
            receiv_flag <= 1'b1;
        else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8) //这里设置为记到BAUD_CNT/9*8是为了让Rx_done信号提前一点产生,
            receiv_flag <= 1'b0;                         //避免因为Rx_done出现过晚,导致错过下一个起始位的下降沿。
    end                                                  //后面和其相同的条件判断,也是因为相同原因设置的。
    
    always @(posedge Clk or negedge Rst_n) begin    //波特计数 
        if(Rst_n == 0)
            baud_cnt <= 0;
        else if(receiv_flag == 1) begin
            if(baud_cnt == BAUD_CNT - 1)
                baud_cnt <= 0;
            else
                baud_cnt <= baud_cnt + 1'b1;
            end
        else
            baud_cnt <= 0;
    end
    
    always @(posedge Clk or negedge Rst_n) begin	//采样计数
        if(Rst_n == 0) begin
            sampel_cnt <= 0;
            sampel_en <= 0;
        end
        else if(receiv_flag == 1) begin
            case(baud_cnt)
                BAUD_CNT/9*1-1 : begin sampel_cnt <= 0; sampel_en <=1; end
                BAUD_CNT/9*2-1 : begin sampel_cnt <= 1; sampel_en <=1; end
                BAUD_CNT/9*3-1 : begin sampel_cnt <= 2; sampel_en <=1; end
                BAUD_CNT/9*4-1 : begin sampel_cnt <= 3; sampel_en <=1; end
                BAUD_CNT/9*5-1 : begin sampel_cnt <= 4; sampel_en <=1; end
                BAUD_CNT/9*6-1 : begin sampel_cnt <= 5; sampel_en <=1; end
                BAUD_CNT/9*7-1 : begin sampel_cnt <= 6; sampel_en <=1; end
                BAUD_CNT/9*8-1 : begin sampel_cnt <= 7; sampel_en <=1; end
                BAUD_CNT/9*9-1 : sampel_cnt <= 0;
                default:sampel_en <=0;
            endcase
        end
    end
    
    always @(posedge Clk or negedge Rst_n) begin    //数据位计数
        if(Rst_n == 0)
            bit_cnt <= 0;
        else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8)
            bit_cnt <= 0;
        else if(baud_cnt == BAUD_CNT - 1)
            bit_cnt <= bit_cnt + 1'b1;
    end
	
    always @(posedge Clk or negedge Rst_n) begin    //接收完成信号产生
        if(Rst_n == 0)
            Rx_done <= 0;
        else if(bit_cnt == 9 & baud_cnt == BAUD_CNT/9*8)
            Rx_done <= 1'b1;
        else
            Rx_done <= 0;
    end
endmodule

4、仿真验证

(1)仿真激励文件

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2022/12/16 21:36:04
// Design Name: 
// Module Name: uart_byte_rx_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

module uart_byte_rx_tb();
    
    reg        CLK_50M;
    reg        RST_N;
    wire [7:0] Data;    
    reg        Uart_rx;
    reg  [7:0] test_data;
    wire       RX_DONE;
    uart_byte_rx 
  # (
        .RX_BAUD   (9600),
        .CLK_FQC   (50_000_000),
        .BAUD_CNT  (50))
    uart_byte_rx_inst
    (
        .Clk        (CLK_50M),
        .Rst_n      (RST_N),
        .Uart_rx    (Uart_rx),
        .Data       (Data),
        .Rx_done    (Rx_done)
    );
    
    
    always #10 CLK_50M  <= ~CLK_50M;
    
    initial begin
    CLK_50M <= 1'b0;
    RST_N   <= 1'b0;
    Uart_rx <= 1'b1;
    test_data <= 8'h0;
    #100
    RST_N   <= 1'b1;
    #20
        test_data <= 8'haf;
        #1000
        Uart_rx <= 1'b0;
        #1000             
        Uart_rx <= test_data[0];
        #1000             
        Uart_rx <= test_data[1];
        #1000             
        Uart_rx <= test_data[2];
        #1000             
        Uart_rx <= test_data[3];
        #1000             
        Uart_rx <= test_data[4];
        #1000             
        Uart_rx <= test_data[5];
        #1000             
        Uart_rx <= test_data[6];
        #1000             
        Uart_rx <= test_data[7];
        #1000             
        Uart_rx <= 1'b1;
        test_data <= 8'h56;
        #1000
        Uart_rx <= 1'b0;
        #1000             
        Uart_rx <= test_data[0];
        #1000             
        Uart_rx <= test_data[1];
        #1000             
        Uart_rx <= test_data[2];
        #1000             
        Uart_rx <= test_data[3];
        #1000             
        Uart_rx <= test_data[4];
        #1000             
        Uart_rx <= test_data[5];
        #1000             
        Uart_rx <= test_data[6];
        #1000             
        Uart_rx <= test_data[7];
        #1000             
        Uart_rx <= 1'b1;
    #2000
    $stop;
    end
    
    
endmodule

(2)仿真结果

有关串口接收模块——verilog实现的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  5. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  6. ruby-on-rails - RSpec:避免使用允许接收的任何实例 - 2

    我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_

  7. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  8. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  9. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  10. ruby-on-rails - 如何使用 Rack 接收 JSON 对象 - 2

    我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":

随机推荐