寫在前面的話
在數字邏輯電路設計中,分頻器是一種基本的電路單元。通常用來對某個給定頻率進行分頻,以得到所需的頻率。分頻在FPGA的設計中一直都擔任着很重要的角色,而說到分頻,我相信很多人都已經想到了利用計數器計數來得到想要的時鍾頻率,但問題是僅僅利用計數器來分頻,只可以實現偶數分頻,而如果需要三分頻、五分頻、七分頻等等奇數類分頻,那應該怎么辦呢?在這里,夢翼師兄為大家介紹一種可以實現任意整數分頻的方法。
實現原理
這種方法同樣也是利用了計數器來實現,當然我們是使用狀態機來實現的。我們首先定義分頻時鍾高電平的個數和低電平的個數,在第一個狀態,當計數器計數值小於分頻時鍾低電平個數的時候,輸出電平為低電平,等於低電平的個數的時候,輸出取反同時計數器清零,跳轉到下一個狀態。在這個狀態當計數器計數小於分頻時鍾高電平個數的時候,輸出電平不變,當計數器數值等於高電平個數的時候,輸出取反同時計數器清零,跳轉到上一個狀態,這樣就可以實現任意分頻。
系統框架
頂層模塊端口描述
端口名 |
端口說明 |
clk |
系統時鍾50Mhz |
rst_n |
系統低電平復位信號 |
clk_out |
輸出分頻時鍾 |
代碼分析
/**************************************************** * Engineer : 夢翼師兄 * QQ : 761664056 * The module function : 任意分頻模塊 *****************************************************/ 01 module divide( 02 clk, //系統時鍾輸入 03 rst_n, //系統低電平復位 04 clk_out //分頻時鍾輸出 05 ); 06 07 parameter HW = 3; //輸出時鍾高電平寬度 08 parameter LW = 2; //輸出時鍾低電平寬度 09 10 input clk; //系統時鍾輸入 11 input rst_n; //系統低電平復位 12 output clk_out; //分頻時鍾輸出 13 14 reg clk_out; 15 reg [31:0] count; //計數器 16 reg state; //狀態寄存器 17 18 always @ (posedge clk or negedge rst_n) 19 begin 20 if (!rst_n) //異步復位 21 begin 22 clk_out <= 1'b0; //賦初值 23 count <= 0; 24 state <= 0; 25 end 26 else 27 case (state) 28 0 : if (count < LW-1) //輸出低電平個數比較器 29 begin 30 count <= count + 1; 31 state <= 0; 32 end 33 else //輸出低電平個數等於設定的低電平個數 34 begin 35 count <= 0; //計數器清零 36 clk_out <= 1'b1; //輸出變為1 37 state <= 1; 38 end 39 40 1 : if (count < HW-1) //輸出高電平個數比較器 41 begin 42 count <= count + 1; 43 state <= 1; 44 end 45 else //輸出高電平個數等於設定的高電平個數 46 begin 47 count <= 0; //計數器清零 48 clk_out <= 1'b0; //輸出變為0 49 state <= 0; 50 end 51 default : state <= 0; 52 endcase 53 end 54 55 endmodule |
第7~8行定義了2個參數,一個是輸出高電平的個數,一個是低電平的個數,比如HW=3,LW=2輸出就是一個5分頻的時鍾,
比如HW=3,LW=3輸出就是一個6分頻的時鍾,可見只要改變HW和LW的值就可以實現任意分頻。第18~53行就是利用狀態機來實現分頻的過程,用2個狀態來計數輸出高電平個數和低電平個數。
編寫測試代碼如下:
/**************************************************** * Engineer : 夢翼師兄 * QQ : 761664056 * The module function : 任意分頻測試模塊 *****************************************************/ 01 `timescale 1ns/1ps //仿真時間單位是ns,仿真時間精度是ps 02 module tb; 03 04 reg clk, rst_n; //仿真激勵時鍾,復位信號 05 06 wire clk_out; //仿真輸出分頻信號 07 08 initial begin 09 clk = 0; //clk時鍾信號初始化 10 rst_n = 0; //rst_n復位信號初始化 11 #200.1 12 rst_n = 1; //200.1ns之后,復位結束 13 end 14 15 always #10 clk = ~clk; //產生50Mhz時鍾信號 16 17 divide divide( //把激勵信號送進diveder模塊 18 .clk(clk), 19 .rst_n(rst_n), 20 .clk_out(clk_out) 21 ); 22 23 endmodule |
仿真分析
我們輸入的時鍾是50Mhz,一個周期是20ns,輸出5分頻的時鍾,周期是100ns,可見我們的設計是正確的。
我們修改分頻模塊的參數將HW改為3,LW改為3,仿真波形如下:
同樣輸入的時鍾是50Mhz,一個周期是20ns,輸出6分頻的時鍾,周期是120ns,可見我們的設計是正確的。