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,取決於默認情況下(一般是指無通信的時候)外部輸入信號是什么電平。

想起以前工程中真的出現過問題,悲哀的教訓,后來仔細想了很久,雖然看上去不難實現,但的確是吸取教訓之后的設計結果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM