1. 程式人生 > >從計數器到分頻電路

從計數器到分頻電路

輸入 程序 減少 soft code cnblogs 能夠 spa 正常

  本文介紹常見的電路——計數器,然後我們由計數器電路講解到分頻電路。

一、計數器

  (1)計數器代碼

  計數器,顧名思義就是在時鐘的節拍下進行計數,一個簡單的N位計數器的代碼如下所示,這個計數器從0計數到2^N - 1(共計數了2^N個數,也就是N位計數器):

 1 module count#(parameter N=8)(
 2 input clk,
 3 input clear,
 4 output[N-1:0] cnt_Q
 5 );
 6 reg[N-1:0] cnt;
 7 assign cnt_Q = cnt;
 8 
 9 always
@(posedge clk) 10 if(clear) 11 cnt <= h0; //同步清 0,高電平有效 12 else 13 cnt <= cnt+1b1; //加法計數 14 15 endmodule

上述描述的計數器通過 clear 信號清除計數值,然後下一周期開始加 1 計數;當計數器計到能夠存儲的最大數值時, 例如本例為 8 個 1,即 8‘hff 就會自動回到 0,然後開始下一輪計數。

綜合得帶的電路如下所示:

技術分享

  (2)計數器改進

  如果想要實現 0~k 範圍內計數,其中k ≠ 2^N ,可以將 always 語句修改為:

always@(posedge clk)
    if(clear)
        cnt <=  h0;    //同步清 0,高電平有效
    else if(cnt==K)
        cnt <= h0;
    else
        cnt <= cnt+1b1; //減法計數            

  

  前面是累加計數,下面是一個既可以遞增也能遞減,且具備初始值裝載和復位的計數器,代碼如下所示:

 1 module updown_count#(parameter N=8)(
 2     input clk,
3 input clear, 4 input load, 5 input up_down, 6 input [N-1:0] preset_D, 7 output[N-1:0] cnt_Q 8 ); 9 reg[N-1:0] cnt; 10 assign cnt_Q = cnt; 11 12 always@(posedge clk) 13 if(clear) 14 cnt <= h0; //同步清 0,高電平有效 15 else if(load) 16 cnt <= preset_D; //同步預置 17 else if(up_down) 18 cnt <= cnt+1; //加法計數 19 else 20 cnt <= cnt-1; //減法計數 21 22 endmodule

二、計數器的用途

  (1)基本的計數功能與分頻

  計數器的基本功能顧名思義就是計數了,用來計數,產生某個信號等等。利用這個功能,可以實現信號的分頻,具體會在後面的分頻電路中進行描述。

  (2)看門狗

  計數器其實就可以設計成看門狗。在初始狀態時,看門狗電路首先裝載一個大數;當狀態機或者程序開始運行後,看門狗開始倒計數。如果狀態機或程序運行正常,每隔一段時間應發出指令或信號讓看門狗重新裝載一個大 初始值,並再次開始倒計數。如果看門狗減到 0 就認為程序或狀態機沒有正常工作,就需要強制整個系統復位。

  上面的第二處改進的計數器電路描述就是一個看門狗電路,只要加上 cnt==0 作為看門復位狀態即可;而 load 信號則是狀態機或軟件給出的餵狗動作。

  (3)特殊的有限狀態機

  當狀態機要求沒有那麽嚴格的時候,這個時候就可以用計數器的計數值當做狀態機的狀態,計數增加或者減少就是改變狀態。

三、分頻電路

  計數器實質是對輸入的驅動時鐘進行計數,所以計數器在某種意義上講,等同於對時鐘進行分頻。例如一個最大計數長度為 N 的計數器,將其最高位作為時鐘輸出(占空比不一定為 1:1),則工作頻率為輸入時鐘的 1/(2N)。通常 ASIC 和 FPGA 中,時鐘都是全局信號,都需要通過 PLL 處理才能使用,但某些簡易場合,采用計數器輸出時鐘也是能夠使用的,只是需要註意時序約束。

從計數器到分頻電路