本文介紹常見的電路——計(jì)數(shù)器,然后我們由計(jì)數(shù)器電路講解到分頻電路。
一、計(jì)數(shù)器
(1)計(jì)數(shù)器代碼
計(jì)數(shù)器,顧名思義就是在時(shí)鐘的節(jié)拍下進(jìn)行計(jì)數(shù),一個(gè)簡(jiǎn)單的N位計(jì)數(shù)器的代碼如下所示,這個(gè)計(jì)數(shù)器從0計(jì)數(shù)到2^N - 1(共計(jì)數(shù)了2^N個(gè)數(shù),也就是N位計(jì)數(shù)器):
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+1'b1; //加法計(jì)數(shù) 14 15 endmodule
上述描述的計(jì)數(shù)器通過(guò)?clear?信號(hào)清除計(jì)數(shù)值,然后下一周期開始加?1?計(jì)數(shù);當(dāng)計(jì)數(shù)器計(jì)到能夠存儲(chǔ)的最大數(shù)值時(shí), 例如本例為?8?個(gè)?1,即?8'hff?就會(huì)自動(dòng)回到?0,然后開始下一輪計(jì)數(shù)。
綜合得帶的電路如下所示:
(2)計(jì)數(shù)器改進(jìn)
如果想要實(shí)現(xiàn)?0~k?范圍內(nèi)計(jì)數(shù),其中k?≠?2^N?,可以將?always?語(yǔ)句修改為:
always@(posedge clk) if(clear) cnt <= 'h0; //同步清 0,高電平有效 else if(cnt==K) cnt <= 'h0; else cnt <= cnt+1'b1; //減法計(jì)數(shù)
前面是累加計(jì)數(shù),下面是一個(gè)既可以遞增也能遞減,且具備初始值裝載和復(fù)位的計(jì)數(shù)器,代碼如下所示:
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; //同步預(yù)置 17 else if(up_down) 18 cnt <= cnt+1; //加法計(jì)數(shù) 19 else 20 cnt <= cnt-1; //減法計(jì)數(shù) 21 22 endmodule
二、計(jì)數(shù)器的用途
(1)基本的計(jì)數(shù)功能與分頻
計(jì)數(shù)器的基本功能顧名思義就是計(jì)數(shù)了,用來(lái)計(jì)數(shù),產(chǎn)生某個(gè)信號(hào)等等。利用這個(gè)功能,可以實(shí)現(xiàn)信號(hào)的分頻,具體會(huì)在后面的分頻電路中進(jìn)行描述。
?。?)看門狗
計(jì)數(shù)器其實(shí)就可以設(shè)計(jì)成看門狗。在初始狀態(tài)時(shí),看門狗電路首先裝載一個(gè)大數(shù);當(dāng)狀態(tài)機(jī)或者程序開始運(yùn)行后,看門狗開始倒計(jì)數(shù)。如果狀態(tài)機(jī)或程序運(yùn)行正常,每隔一段時(shí)間應(yīng)發(fā)出指令或信號(hào)讓看門狗重新裝載一個(gè)大的初始值,并再次開始倒計(jì)數(shù)。如果看門狗減到 0?就認(rèn)為程序或狀態(tài)機(jī)沒(méi)有正常工作,就需要強(qiáng)制整個(gè)系統(tǒng)復(fù)位。
上面的第二處改進(jìn)的計(jì)數(shù)器電路描述就是一個(gè)看門狗電路,只要加上?cnt==0?作為看門復(fù)位狀態(tài)即可;而?load?信號(hào)則是狀態(tài)機(jī)或軟件給出的喂狗動(dòng)作。
?。?)特殊的有限狀態(tài)機(jī)
當(dāng)狀態(tài)機(jī)要求沒(méi)有那么嚴(yán)格的時(shí)候,這個(gè)時(shí)候就可以用計(jì)數(shù)器的計(jì)數(shù)值當(dāng)做狀態(tài)機(jī)的狀態(tài),計(jì)數(shù)增加或者減少就是改變狀態(tài)。
三、分頻電路
(1)簡(jiǎn)單的計(jì)數(shù)器
計(jì)數(shù)器實(shí)質(zhì)是對(duì)輸入的驅(qū)動(dòng)時(shí)鐘進(jìn)行計(jì)數(shù),所以計(jì)數(shù)器在某種意義上講,等同于對(duì)時(shí)鐘進(jìn)行分頻。例如一個(gè)最大計(jì)數(shù)長(zhǎng)度為N=2^n(從0計(jì)數(shù)到N-1)的計(jì)數(shù)器,也就是寄存器位數(shù)位n,那么寄存器最高位的輸出為N=2^n分頻,次高位為N/2分頻...例如下面的代碼:
1 module test#(parameter N=3)( 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 7 reg [N-1:0] div_reg ;//分頻計(jì)數(shù)器 8 always @(posedge clk or negedge rst_n) 9 if (rst_n == 1'b0 ) 10 div_reg <= 0 ; 11 else 12 div_reg <= div_reg + 1'b1 ; 13 14 assign clk_div = div_reg[N-1] ; 15 16 17 endmodule
該代碼描述的將一個(gè)3位的計(jì)數(shù)器最高位輸出,也就是計(jì)數(shù)長(zhǎng)度為8(計(jì)數(shù)從0~7)波形如下所示:
可以看到最高位的輸出為輸入時(shí)鐘的8分頻。
當(dāng)N不是2的整數(shù)次冪時(shí),即N≠2^n時(shí),從0計(jì)數(shù)到N-1,其最高位作為時(shí)鐘輸出(占空比不一定為 1:1)是輸入時(shí)鐘的1/N,也就是N分頻。我們來(lái)舉個(gè)例子,比如最大計(jì)數(shù)長(zhǎng)度為5的計(jì)數(shù)器,即從0計(jì)數(shù)到4后又返回0,那么需要定義一個(gè)三位的寄存器。寄存器的計(jì)數(shù)過(guò)程為:
000-001-010-011-100-000-001-010-011-100-000-001-010-011-100-000-001-010-011-100······
我們?nèi)∽罡呶?,得到的信?hào)變化就是:
0-0-0-0-1-0-0-0-0-0-1-0-0-0-0-1-0-0-0-0-1···
代碼如下所示:
1 module test#(parameter N=3)( 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 7 reg [N-1:0] div_reg ;//分頻計(jì)數(shù)器 8 always @(posedge clk or negedge rst_n) 9 if (rst_n == 1'b0 ) 10 div_reg <= 0 ; 11 else if(div_reg == 3'd4)//從0計(jì)數(shù)到4,然后返回到0,5分頻 12 div_reg <= 0; 13 else 14 div_reg <= div_reg + 1'b1 ; 15 16 assign clk_div = div_reg[N-1] ; 17 18 19 endmodule
仿真波形如下所示:
由此可以看到,每一個(gè)分頻后的時(shí)鐘周期=5倍原來(lái)的時(shí)鐘周期,因此是5分頻。
那么這個(gè)情況是不是也可以包含第一種情況呢?我們那設(shè)置為8分頻看看,即前面的3'd4改成3'd7,得到的仿真波形如下所示:
可以看到,計(jì)數(shù)器的最高位輸出也是輸入頻率的1/N。
因此我們得到結(jié)論:一個(gè)最大計(jì)數(shù)長(zhǎng)度為N(從0計(jì)數(shù)到N-1)的計(jì)數(shù)器,其最高位的輸出,是輸入頻率的N分頻。
通常?ASIC?和?FPGA?中,時(shí)鐘都是全局信號(hào),都需要通過(guò)?PLL?處理才能使用,但某些簡(jiǎn)易場(chǎng)合,采用計(jì)數(shù)器輸出時(shí)鐘也是能夠使用的,只是需要注意時(shí)序約束。
(2)偶數(shù)倍分頻(占空比50%)
偶數(shù)分頻,也就是2分頻、4分頻、6分頻...這個(gè)還是比較簡(jiǎn)單的,N(N當(dāng)然是2的倍數(shù))分頻,那么計(jì)數(shù)到N/2-1,然后時(shí)鐘翻轉(zhuǎn):
例如N=6時(shí),代碼如下所示:
1 module test#(parameter N=6)( 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 reg div_reg ; 7 reg [N-1:0] div_cnt ;//分頻計(jì)數(shù)器 8 always @(posedge clk or negedge rst_n) 9 if (rst_n == 1'b0 )begin 10 div_cnt <= 0 ; 11 div_reg <= 0 ; 12 end 13 else if(div_cnt == (N/2 - 1))begin 14 div_cnt <= 0; 15 div_reg <= ~div_reg ; 16 end 17 else 18 div_cnt <= div_cnt + 1'b1 ; 19 20 assign clk_div = div_reg ;
仿真波形如下所示:
當(dāng)N=2的仿真波形如下所示:
(3)奇數(shù)倍分頻
①占空比接近50%
對(duì)于占空比不是50%的計(jì)數(shù)分頻,我們可以直接用上面的計(jì)數(shù)器方法,這里就不說(shuō)了,我們介紹其他接近50%的占空比的方法,比如下面使用的狀態(tài)機(jī)分頻:
上圖的狀態(tài)機(jī)除了用一般的狀態(tài)機(jī)設(shè)計(jì)方式之外,我們也可以用簡(jiǎn)單的計(jì)數(shù)器實(shí)現(xiàn),這種方法如下所示:
假設(shè)時(shí)鐘分頻是N,則設(shè)置一個(gè)計(jì)數(shù)器,計(jì)數(shù)長(zhǎng)度是N(即從0計(jì)數(shù)到N-1),然后在計(jì)數(shù)器為計(jì)數(shù)到(N-1)/2的時(shí)候,翻轉(zhuǎn)一下分頻時(shí)鐘信號(hào);在計(jì)數(shù)器計(jì)數(shù)到為N-1的時(shí)候,再翻轉(zhuǎn)一下時(shí)鐘。
代碼如下所示:
1 module test#(parameter N=3)(//N分頻,這里是3分頻 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 7 reg [N-1:0] div_cnt ;//分頻計(jì)數(shù)器 8 reg div_reg ; 9 always @(posedge clk or negedge rst_n)begin 10 if (rst_n == 1'b0 )begin 11 div_cnt <= 0 ; 12 div_reg <= 1 ; 13 end else if (div_cnt == (N-1)/2)begin//計(jì)數(shù)到(N-1)/2,進(jìn)行翻轉(zhuǎn)和繼續(xù)計(jì)數(shù) 14 div_reg <= ~div_reg; 15 div_cnt <= div_cnt + 1'b1 ; 16 end else if ( div_cnt == (N-1) )begin//計(jì)數(shù)到N-1,進(jìn)行清零和翻轉(zhuǎn) 17 div_cnt <= 0 ; 18 div_reg <= ~div_reg; 19 end else 20 div_cnt <= div_cnt + 1'b1 ; 21 22 end 23 assign clk_div = (N == 1)?clk:div_reg ;//注意這里 24 25 26 endmodule
代碼中我們需要注意,在N= 1的情況,也就是不分頻的情況。仿真電路如下圖所示:
3分頻,N = 3:
5分頻,N= 5 :
不分頻,即N=1的仿真如下所示:
②占空比50%
產(chǎn)生具有50%占空比的奇數(shù)分頻時(shí)鐘的算法如下所示,假設(shè)N分頻(N是計(jì)數(shù)):
設(shè)置一個(gè)計(jì)數(shù)長(zhǎng)度為N的上升沿計(jì)數(shù)器,和一個(gè)信號(hào)寄存器;信號(hào)寄存器在上升沿計(jì)數(shù)器為(N-1)/2的時(shí)候進(jìn)行翻轉(zhuǎn),然后再在計(jì)數(shù)到N-1的時(shí)候進(jìn)行翻轉(zhuǎn)(這里相當(dāng)于得到一個(gè)N分頻信號(hào)A)。
再設(shè)置一個(gè)計(jì)數(shù)長(zhǎng)度為N的下降沿計(jì)數(shù)器,和另一個(gè)信號(hào)寄存器;信號(hào)寄存器在下降沿計(jì)數(shù)器為(N-1)/2的時(shí)候進(jìn)行翻轉(zhuǎn),然后再在計(jì)數(shù)到N-1的時(shí)候進(jìn)行翻轉(zhuǎn)(這里相當(dāng)于得到一個(gè)N分頻信號(hào)B)。
將A和B相或就可以得到占空比50%的奇數(shù)分頻信號(hào);代碼實(shí)現(xiàn)如下:
1 module test#(parameter N=5)(//N分頻 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 7 reg sig_r ;//定義一個(gè)上升沿翻轉(zhuǎn)的信號(hào) 8 reg sig_f ;//定義一個(gè)下降沿翻轉(zhuǎn)的信號(hào) 9 reg [N-1:0] cnt_r;//上升沿計(jì)數(shù)器 10 reg [N-1:0] cnt_f;//下降沿計(jì)數(shù)器 11 12 wire clk_f ; 13 assign clk_f = ~clk ;//用來(lái)觸發(fā)下降沿計(jì)數(shù)器的時(shí)鐘 14 //由于同時(shí)使用上升沿和下降沿觸發(fā)器不好,因此我們?yōu)橥贿呇?,都使用上升沿觸發(fā) 15 //只不過(guò)是將時(shí)鐘進(jìn)行反向 16 17 always @(posedge clk or negedge rst_n)begin//上升沿計(jì)數(shù) 18 if(rst_n == 1'b0)begin 19 sig_r <= 0 ; 20 cnt_r <= 0 ; 21 end else if( cnt_r == (N-1)/2 )begin 22 sig_r <= ~sig_r ; 23 cnt_r <= cnt_r + 1 ; 24 end else if ( cnt_r == (N-1) )begin 25 sig_r <= ~sig_r ; 26 cnt_r <= 0 ; 27 end else 28 cnt_r <= cnt_r + 1 ; 29 end 30 31 always @(posedge clk_f or negedge rst_n)begin//下降沿計(jì)數(shù) 32 if(rst_n == 1'b0)begin 33 sig_f <= 0 ; 34 cnt_f <= 0 ; 35 end else if( cnt_f == (N-1)/2 )begin 36 sig_f <= ~sig_f ; 37 cnt_f <= cnt_f + 1 ; 38 end else if ( cnt_f == (N-1) )begin 39 sig_f <= ~sig_f ; 40 cnt_f <= 0 ; 41 end else 42 cnt_f <= cnt_f + 1 ; 43 end 44 45 assign clk_div = sig_f || sig_r ; 46 47 endmodule
仿真波形如下所示:
3分頻:
5分頻:
(4)任意整數(shù)倍分頻(接近50%)
在前面中,我們知道了一個(gè)最大計(jì)數(shù)長(zhǎng)度為N(從0計(jì)數(shù)到N-1)的計(jì)數(shù)器,其最高位的輸出,是輸入頻率的N分頻,因此最簡(jiǎn)單的任意分頻電路就是設(shè)計(jì)一個(gè)計(jì)數(shù)器,然后最高位輸出就是分頻的頻率了。雖然這這種方法很簡(jiǎn)單,但是很顯然,這種方法的占空比是很糟糕的。因此我們要用其他的方法,也就是用其他的組合方式。
①占空比接近50%任意整數(shù)分頻
這種方法是取自偶數(shù)分頻和奇數(shù)分頻里面的接近50%占空比,實(shí)現(xiàn)的代碼如下所示:
1 module test #( parameter cfactor= 5)( 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 reg clk_loc; 7 //reg [15:0] cnt;//allowed maximum clock division factor is 65536 8 reg [7:0] cnt;//allowed maximum clock division factor is 256 9 10 assign clk_div = (cfactor==1)? clk : clk_loc; 11 //assign clk_div = ((rst==1) || (cfactor==1))? clk : clk_loc; 12 13 always@(posedge clk or negedge rst_n) 14 if(!rst_n)begin 15 cnt <= 'd0; 16 clk_loc = 1; 17 end 18 else begin 19 cnt <= cnt + 1'b1; 20 if(cnt==cfactor/2-1) 21 clk_loc = 0; 22 else if(cnt==cfactor-1) begin 23 cnt <= 'd0; 24 clk_loc = 1; 25 end 26 end 27 28 endmodule
2分頻的仿真圖,如下所示:
5分頻的仿真波形如下所示:
②占空比50%的任意整數(shù)分頻(重點(diǎn))
這種方法是取自偶數(shù)分頻和奇數(shù)分頻都是50%占空比的組合,代碼如下所示:
1 module test#(parameter N=1)(//N分頻 2 input clk, 3 input rst_n, 4 output clk_div 5 ); 6 7 //奇數(shù)分頻 8 reg sig_r ;//定義一個(gè)上升沿翻轉(zhuǎn)的信號(hào) 9 reg sig_f ;//定義一個(gè)下降沿翻轉(zhuǎn)的信號(hào) 10 reg [N-1:0] cnt_r;//上升沿計(jì)數(shù)器 11 reg [N-1:0] cnt_f;//下降沿計(jì)數(shù)器 12 13 wire clk_f ; 14 assign clk_f = ~clk ;//用來(lái)觸發(fā)下降沿計(jì)數(shù)器的時(shí)鐘 15 //由于同時(shí)使用上升沿和下降沿觸發(fā)器不好,因此我們?yōu)橥贿呇兀际褂蒙仙赜|發(fā) 16 //只不過(guò)是將時(shí)鐘進(jìn)行反向 17 18 always @(posedge clk or negedge rst_n)begin//上升沿計(jì)數(shù) 19 if(rst_n == 1'b0)begin 20 sig_r <= 0 ; 21 cnt_r <= 0 ; 22 end 23 else begin 24 cnt_r <= cnt_r + 1 ; 25 if( cnt_r == (N-1)/2 )begin 26 sig_r <= ~sig_r ; 27 end else if ( cnt_r == (N-1) )begin 28 sig_r <= ~sig_r ; 29 cnt_r <= 0 ; 30 end 31 end 32 end 33 34 always @(posedge clk_f or negedge rst_n)begin//下降沿計(jì)數(shù) 35 if(rst_n == 1'b0)begin 36 sig_f <= 0 ; 37 cnt_f <= 0 ; 38 end 39 else begin 40 cnt_f <= cnt_f + 1 ; 41 if( cnt_f == (N-1)/2 )begin 42 sig_f <= ~sig_f ; 43 end else if ( cnt_f == (N-1) )begin 44 sig_f <= ~sig_f ; 45 cnt_f <= 0 ; 46 end 47 end 48 end 49 50 //偶數(shù)分頻 51 reg div_reg ; 52 reg [N-1:0] div_cnt ;//分頻計(jì)數(shù)器 53 always @(posedge clk or negedge rst_n)begin 54 if (rst_n == 1'b0 )begin 55 div_cnt <= 0 ; 56 div_reg <= 0 ; 57 end 58 else begin 59 div_cnt <= div_cnt + 1'b1 ; 60 if(div_cnt == (N/2 - 1))begin 61 div_cnt <= 0; 62 div_reg <= ~div_reg ; 63 end 64 end 65 end 66 assign clk_div = (N == 1)?clk: 67 ( N%2 == 1)?(sig_f || sig_r ): div_reg;//這里用來(lái)輸出分頻值。對(duì)2的取余操作是綜合的 68 69 endmodule
仿真波形如下所示:
5分頻:
6分頻:
總結(jié):本文介紹了計(jì)數(shù)器及其功能,主要是介紹了作為分頻器的功能。對(duì)于分頻器,如下所示:
編輯:hfy
評(píng)論