一、引言
在數字邏輯電路設計中,分頻器是一種基本的電路單元。通常用來對某個給定頻率進行分頻,以得到我們想要的頻率。在FPGA中,我們一般都是通過計數器來實現分頻,分頻得到的時鍾質量沒有通過PLL得到的時鍾質量好,用於對時鍾信號要求較高的邏輯設計中,還是用PLL分頻比較好。下面將詳細介紹任意偶數分頻,奇數分頻,小數分頻。
二、偶數分頻
以四分頻為例,假設系統時鍾頻率為 50MHz,那么周期為 20ns,四分頻之后得到的時鍾頻率為 12.5MHz,時鍾周期為 80ns。在50MHz的系統時鍾的驅動下,計數器要在計數到 40 ns ,輸出時鍾翻轉,計數到40 ns時,計數器的值為1,剛好計數兩下。
代碼如下:

1 // ********************************************************************************* 2 // Project Name : even_divclk 3 // Email : 4 // Create Time : 2020/07/07 9:59 5 // Module Name : even_divclk 6 // editor : qing 7 // Version : Rev1.0.0 8 // Description : 任意占空比為50%的偶數分頻 9 // ********************************************************************************* 10 11 module even_divclk( 12 input sclk , // System clk 50MHz 13 input s_rst_n , 14 15 output reg div_clk 16 ); 17 18 //========================================================================\ 19 // =========== Define Parameter and Internal signals =========== 20 //========================================================================/ 21 22 // parameter n = ; 23 parameter n = 4 ; // just for test 24 25 reg [19:0] cnt ; 26 27 always @ (posedge sclk or negedge s_rst_n) begin // cnt 28 if(s_rst_n == 1'b0) 29 cnt <= 0; 30 else if(cnt == n/2 - 1) 31 cnt <= 0; 32 else 33 cnt <= cnt + 1'b1; 34 end 35 36 always @ (posedge sclk or negedge s_rst_n) begin 37 if(s_rst_n == 1'b0) 38 div_clk <= 1'b0; 39 else if(cnt == n/2 - 1) 40 div_clk <= ~div_clk; 41 else 42 div_clk <= div_clk; 43 end 44 45 endmodule
testbench:

1 // ********************************************************************************* 2 // Project Name : even_divclk 3 // Email : 4 // Create Time : 2020/07/07 10:10 5 // Module Name : even_divclk_tb 6 // editor : qing 7 // Version : Rev1.0.0 8 // ********************************************************************************* 9 `timescale 1ns/1ps 10 module even_divclk_tb; 11 reg sclk ; 12 reg s_rst_n ; 13 wire div_clk ; 14 15 even_divclk even_divclk_inst( 16 .sclk (sclk ), 17 .s_rst_n(s_rst_n ), 18 .div_clk(div_clk ) 19 ); 20 21 initial 22 sclk = 1'b0; 23 always #10 sclk = ~sclk; 24 25 initial 26 begin 27 #1; 28 s_rst_n = 1'b0; 29 #21; 30 s_rst_n = 1'b1; 31 end 32 33 endmodule
Modelsim仿真結果:
由圖可見,達到預期目的。
三、奇數分頻
奇數分頻需要通過兩個輔助時鍾來生成,如上圖所示,以占空比為 50% 的 5 分頻為例,分頻得到的信號 div_clk = clk_p | clk_n。
假設分頻系數為 n,那么 clk_p 在 在時鍾信號的上升沿的驅動下第 (n - 1)/2 - 1 個時鍾的上升沿翻轉一次,在(n - 1)個時鍾的上升沿的時候再翻轉一次;clk_n 則是在時鍾信號的下降沿的驅動下,在第(n - 1)/2 - 1個時鍾的下降沿翻轉一次,在( n - 1)個時鍾的時候再翻轉一次,將 clk_p 與 clk_n 做或運算得到 div_clk。
下面是一個占空比為 50% 的5分頻的例程。

1 // ********************************************************************************* 2 // Project Name : odd_divclk 3 // Email : 4 // Create Time : 2020/07/07 11:12 5 // Module Name : odd_divclk 6 // editor : qing 7 // Version : Rev1.0.0 8 // Description : 任意占空比為 50% 的奇數分頻 9 // ********************************************************************************* 10 11 module odd_divclk( 12 input sclk , // System clk 50MHz 13 input s_rst_n , 14 15 output div_clk 16 ); 17 //========================================================================\ 18 // =========== Define Parameter and Internal signals =========== 19 //========================================================================/ 20 21 parameter n = 5 ; 22 23 reg [19:0] cnt1 ; 24 reg [19:0] cnt2 ; 25 reg clk_p ; 26 reg clk_n ; 27 28 //============================================================================= 29 //**************************** Main Code ******************************* 30 //============================================================================= 31 32 always @ (posedge sclk or negedge s_rst_n) begin // cnt1 33 if(s_rst_n == 1'b0) 34 cnt1 <= 0; 35 else if(cnt1 == n - 1) 36 cnt1 <= 0; 37 else 38 cnt1 <= cnt1 + 1'b1; 39 end 40 41 always @ (posedge sclk or negedge s_rst_n) begin // cnt2 42 if(s_rst_n == 1'b0) 43 clk_p <= 1'b1; 44 else if(cnt1 == (n-1)/2-1) 45 clk_p <= ~clk_p; 46 else if(cnt1 == (n-1)) 47 clk_p <= ~clk_p; 48 end 49 50 always @ (negedge sclk or negedge s_rst_n) begin // cnt2 51 if(s_rst_n == 1'b0) 52 cnt2 <= 0; 53 else if(cnt2 == n - 1) 54 cnt2 <= 0; 55 else 56 cnt2 <= cnt2 + 1'b1; 57 end 58 59 always @ (negedge sclk or negedge s_rst_n) begin // cnt2 60 if(s_rst_n == 1'b0) 61 clk_n <= 1'b1; 62 else if(cnt2 == (n-1)/2-1) 63 clk_n <= ~clk_n; 64 else if(cnt2 == n - 1) 65 clk_n <= ~clk_n; 66 end 67 68 assign div_clk = clk_p | clk_n; 69 70 endmodule
testbench

1 // ********************************************************************************* 2 // Project Name : even_divclk 3 // Email : 4 // Create Time : 2020/07/07 10:10 5 // Module Name : even_divclk_tb 6 // editor : qing 7 // Version : Rev1.0.0 8 // ********************************************************************************* 9 `timescale 1ns/1ps 10 module even_divclk_tb; 11 reg sclk ; 12 reg s_rst_n ; 13 wire div_clk ; 14 15 odd_divclk odd_divclk_inst( 16 .sclk (sclk ), 17 .s_rst_n(s_rst_n ), 18 .div_clk(div_clk ) 19 ); 20 21 initial 22 sclk = 1'b0; 23 always #10 sclk = ~sclk; 24 25 initial 26 begin 27 #1; 28 s_rst_n = 1'b0; 29 #21; 30 s_rst_n = 1'b1; 31 end 32 33 endmodule
Modelsim仿真結果
四、小數分頻
未完待續······