zoukankan      html  css  js  c++  java
  • verilog抓外部低频输入信号的上升沿和下降沿

      版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址
    
      http://www.cnblogs.com/Colin-Cai/p/7220107.html 
    
      作者:窗户
    
      QQ:6679072
    
      E-mail:6679072@qq.com
    

      已经很久很久很久,没有真正在正式工作中设计过数字电路,有的只是在业余的时候玩玩。

      想起最早的时候,学习数字电路设计,用的是原理图。习惯于用原理图去思考,后来用VHDL,再后来习惯了verilog那和C语言一样的运算符以及简洁的表达,不再喜欢VHDL的累赘。之所以用HDL,最初的想法仅仅是因为原理图画起来累,理解起来繁琐且不便于修改罢了,脑子里最开始总是不断在真实电路和HDL代码中映射。

      现在EDA的技术越来越发达,我一朋友从事IC设计,却从来不理解原理图设计,让我一度匪夷所思,后来想想可能只是因为他没有经历过我们以前那个阶段罢了。

      闲话不多说了,回到这个主题,这其实是数字设计中经常遇到的问题。初学者看到的就是,这还不简单,直接把这个信号引入当D触发器的时钟,结果超复杂的异步设计,陷入万劫深渊无法自拔,这还没包括外部信号可能会有干扰而产生毛刺。

      首先,我们要先默认,外部输入的信号频率要低过主频,否则无法处理,其次,外部输入的信号是可能会有毛刺的。

      

      如上所示是一个毛刺,不能当时发生了上升沿。

      如上所示,只是上升沿的过程出现了毛刺,不能当成是多个上升沿发生。

      那么我们得想办法把毛刺过滤。毛刺发生的情况并不多,于是我们就想,每次系统时钟上升沿(或下降沿)的时候都对外部数字信号采样,当外部真正的电平(也就是去掉毛刺之后)是低电平的时候,采样也绝大多数都是低电平,采到高电平的毛刺是凤毛麟角,高电平也同理。

      再进一步我们就会想,如果连续采到n个电平是高电平,那么实际电平就是高电平;反之,如果连续采到n个电平是低电平,那么实际电平就是低电平;如果连续抓的n个电平有高有低,则实际电平就是之前保持的。

      如此就得到了过滤毛刺之后的真实信号,然后再用真实信号连续两个系统时钟的值来判断上升沿下降沿。

      于是有了如下设计

    `timescale 1ns / 1ns
    module top
    (
     nRst,
     clk,
     in,
     en_posedge
    );
    input nRst, clk, in;
    output en_posedge;
    
    parameter W=3;
    reg [W-1:0]in_reg;
    always@(negedge nRst or posedge clk)
    if(!nRst)
            in_reg <= {W{1'b0}};
    else
            in_reg <= {in_reg[W-2:0], in};
    
    reg in_filter, in_filter_last;
    always@(negedge nRst or posedge clk)
    if(!nRst)
            in_filter <= 1'b0;
    else case({&in_reg, |in_reg})
            2'b00: in_filter <= 1'b0;
            2'b11: in_filter <= 1'b1;
            default: in_filter <= in_filter;
            endcase
    
    always@(negedge nRst or posedge clk)
    if(!nRst)
            in_filter_last <= 1'b0;
    else
            in_filter_last <= in_filter;
    
    reg en_posedge;
    always@(negedge nRst or posedge clk)
    if(!nRst)
            en_posedge <= 1'b0;
    else if((!in_filter_last) & in_filter)
            en_posedge <= 1'b1;
    else
            en_posedge <= 1'b0;
    
    endmodule

    所描述的电路长这样

     

    再来做一个testbench

    `timescale 1ns / 1ns
    module tb;
    reg nRst, clk, in;
    wire en_posedge;
    
    top t
    (
     nRst,
     clk,
     in,
     en_posedge
    );
    
    initial
    forever
    begin
    clk = 0;
    #10;
    clk = 1;
    #10;
    end
    
    initial
    begin
    in=0;
    nRst=1;
    #5;
    nRst=0;
    #20;
    nRst=1;
    #1000;
    in=1;
    #20;
    in=0;
    #1000;
    repeat(3)
            begin
            in=1;
            #20;
            in=0;
            #20;
            end
    in=1;
    #1000;
    $stop;
    end
    
    
    endmodule

     仿真图如下

    只认出了一次上升沿。抓取下降沿同理。

    再来说说设计中的

    parameter W=3;

    这里的W代表着,设计可以过滤掉小于W-1个系统时钟周期的毛刺。

    另外,in_reg和in_filter、in_filter_last要么全1要么全0,取决于默认情况下(一般是指无通信的时候)外部输入信号是什么电平。

    想起以前工程中真的出现过问题,悲哀的教训,后来仔细想了很久,虽然看上去不难实现,但的确是吸取教训之后的设计结果。

  • 相关阅读:
    php7.1安装
    nginx 的限制连接模块limit_zone与limit_req_zone
    selinux导致docker启动失败
    docker学习笔记
    kvm虚拟机
    ZooKeeper在线迁移
    启动EMQ(emqtt)时报错找不到libsctp.so.1
    Linux Samba服务主配文件smb.conf中文详解
    python-day7-字符串类型的内置方法
    python-day7-数字类型的内置方法
  • 原文地址:https://www.cnblogs.com/Colin-Cai/p/7220107.html
Copyright © 2011-2022 走看看