特別注意:在PFGA中能用全局時鍾資源clk就用全局時鍾資源,盡量避免用這種分頻出來的時鍾作為時鍾源,因為這種分頻出來的時鍾走的不是快速通道,信號到別的寄存器這一段路程會產生相對較大的延遲。
//這部分代碼有錯,僅用於分析,不可用於仿真
module division( input clk, input rst_n, output sclk //分頻后的時鍾 ); paramater N = SYS_CLK/SCLK ; //N表示幾分頻系數,當前系統時鍾頻率/所需模塊時鍾頻率 //reg define reg [7:0] cnt //僅支持2 ~ 128 的偶數分頻 //cnt計數模塊 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意這里是個小於符號,計數器cnt進行0--N-1循環計數 cnt <= cnt + 1'b1; else cnt <= 1'd0; end //分頻模塊 always@(posedge clk or negedge rst_n)begin if(!rst_n) sclk <= 1'd1; else if(cnt == N >> 1) //注意N>>1代表M向右平移一位,即N/2; N >> 2代表M向右平移兩位,即N/4;......... sclk <= 1'b0; else if(cnt == 1'b0) sclk <= 1'b1; else sclk <= sclk ; end //假如用產生的sclk信號作為觸發信號去驅動別的模塊,則會產生一定的延遲。避免用這種分頻出來的時鍾作為時鍾源,因為這種分頻出來的時鍾走的不是快速通道,信號到別的寄存器這一段路程會產生相對較大的延遲。 always@(posedge sclk or negedge rst_n)begin if(!rst_n) sclk <= 1'd1; else if(cnt == ......) ....; else if(cnt == ......) ....; else ....; end //上面的always塊程序會產生延遲,應該用以下的形式 always@(posedge clk )begin case(cnt) 0 : sclk <= 1'b0 ; 1 : .... 2 : sclk <= 1'b1; ... ... //根據cnt計數器來變換sclk和執行其它條件 ... end endmodule
分頻器設計:

以下為分頻器設計代碼:
當分頻系數N = sys_clk/scl_clk(系統系統時鍾頻率/模塊所需時鍾頻率)為偶數時:(只能實現2,4,6,8......128分頻)
/**********************.v文件************************/ module Division( input clk, input rst_n, output reg sclk //分頻后的時鍾 ); parameter SYS_CLK = 25_000_000; parameter SCLK = 12500_000; parameter N = SYS_CLK/SCLK; //N表示幾分頻系數,當前系統時鍾頻率/所需模塊時鍾頻率 //reg define reg [7:0] cnt; //僅支持2 ~ 128 的偶數分頻 //cnt計數模塊 always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 8'd0; else if(cnt < N - 1) //注意這里是個小於符號,計數器cnt進行0--N-1循環計數 cnt <= cnt + 1'b1; else cnt <= 8'd0; end //分頻模塊 always@(posedge clk or negedge rst_n)begin if(!rst_n) sclk <= 1'b1; else if(cnt == (N >> 1)) //注意N>>1代表N向右平移一位,即N/2; N >> 2代表N向右平移兩位,即N/4;......... sclk <= 1'b0; else if(cnt == 8'd0) sclk <= 1'b1; else sclk <= sclk; end endmodule /*************************tb文件***********************/ `timescale 1ns/1ps `define period_clk 20 module tb; reg sys_clk; reg sys_rst_n; wire sclk; /*---------------例化DDS模塊------------------*/ Division #(.N(2)//, // .SYS_CLK(25_000_000) ) Division( .clk(sys_clk), .rst_n(sys_rst_n), .sclk(sclk) ); initial sys_clk = 1'b1; always #(`period_clk/2) sys_clk = ~sys_clk; initial begin sys_rst_n = 1'b0; #10; sys_rst_n = 1'b1; #1_000; $stop; end endmodule
當N=2,分頻系數為2時下的仿真波形:

計數器設計:

上圖為cnt計數器計數N = 5個數的波形;即 cnt < N - 1 ;
計數器設計時應該注意的事情:假如要計數N個數:
always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意這里是個小於符號 cnt <= cnt + 1'b1; else cnt <= 1'd0; end
假如在計數滿N個數時,需要執行別的事情:
always@(posedge clk or negedge rst_n)begin if(!rst_n) cnt <= 1'd0; esle if(cnt < N - 1) //注意這里是個小於符號 cnt <= cnt + 1'b1; else cnt <= 1'd0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) ..... esle if(cnt == N - 1) ..... else ..... end
當分頻系數N = sys_clk/scl_clk(系統系統時鍾頻率/模塊所需時鍾頻率)為奇數時:

