用verilog語言寫的任意整數的分頻器


占空比:對於一串理想的脈沖序列中(如方波),正脈沖的持續時間與脈沖總周期的比值,叫做這個方波的占空比。

 

分頻分為奇分頻和偶分頻

第一,偶數倍分頻:偶數倍分頻應該是大家都比較熟悉的分頻,通過計數器計數是完全可以實現的。如進行N倍偶數分頻,那么可以通過由待分頻的時鍾觸發 計數器計數,當計數器從0計數到N/2-1時,輸出時鍾進行翻轉,並給計數器一個復位信號,使得下一個時鍾從零開始計數。以此循環下去。這種方法可以實現 任意的偶數分頻。

    第二:奇數倍分頻:奇數倍分頻常常在論壇上有人問起,實際上,奇數倍分頻有兩種實現方法:首先,完全可以通過計數器來實現,如進行三分頻,通過待分頻時鍾 上升沿觸發計數器進行模三計數,當計數器計數到鄰近值進行兩次翻轉,比如可以在計數器計數到1時,輸出時鍾進行翻轉,計數到2時再次進行翻轉。即是在計數 值在鄰近的1和2進行了兩次翻轉。這樣實現的三分頻占空比為1/3或者2/3。如果要實現占空比為50%的三分頻時鍾,可以通過待分頻時鍾下降沿觸發計 數,和上升沿同樣的方法計數進行三分頻,然后下降沿產生的三分頻時鍾和上升沿產生的時鍾進行相或運算,即可得到占空比為50%的三分頻時鍾。這種方法可以 實現任意的奇數分頻。歸類為一般的方法為:對於實現占空比為50%的N倍奇數分頻,首先進行上升沿觸發進行模N計數,計數選定到某一個值進行輸出時鍾翻 轉,然后經過(N-1)/2再次進行翻轉得到一個占空比非50%奇數n分頻時鍾。再者同時進行下降沿觸發的模N計數,到和上升沿觸發輸出時鍾翻轉選定值相 同值時,進行輸出時鍾時鍾翻轉,同樣經過(N-1)/2時,輸出時鍾再次翻轉生成占空比非50%的奇數n分頻時鍾。兩個占空比非50%的n分頻時鍾相或運 算,得到占空比為50%的奇數n分頻時鍾。另外一種方法:對進行奇數倍n分頻時鍾,首先進行n/2分頻(帶小數,即等於(n-1)/2+0.5),然后再 進行二分頻得到。得到占空比為50%的奇數倍分頻。

     下面講講進行小數分頻的設計方法:

     第三 ,小數分頻:首先講講如何進行n+0.5分頻,這種分頻需要對輸入時鍾進行操作。基本的設計思想:對於進行n+0.5分頻,首先進行模n的計數,在計數到 n-1時,輸出時鍾賦為‘1’,回到計數0時,又賦為0,因此,可以知道,當計數值為n-1時,輸出時鍾才為1,因此,只要保持計數值n-1為半個輸入時 鍾周期,即實現了n+0.5分頻時鍾,因此保持n-1為半個時鍾周期即是一個難點。從中可以發現,因為計數器是通過時鍾上升沿計數,因此可以在計數為n- 1時對計數觸發時鍾進行翻轉,那么時鍾的下降沿變成了上升沿。即在計數值為n-1期間的時鍾下降沿變成了上升沿,則計數值n-1只保持了半個時鍾周期,由 於時鍾翻轉下降沿變成上升沿,因此計數值變為0。因此,每產生一個n+0.5分頻時鍾的周期,觸發時鍾都是要翻轉一次。設計思路如下:

下面是任意正整數的分頻/*此時舉例是6倍頻*/

//divn.v / Verilog

module divn    (
input clk,
input rst_n,
output o_clk
);

parameter WIDTH = 3;
parameter N     = 6;

reg [WIDTH-1:0] cnt_p;// 上升沿計數單位
reg [WIDTH-1:0] cnt_n;// 下降沿計數單位
reg             clk_p;// 上升沿時鍾
reg             clk_n;// 下降沿時鍾

assign o_clk = (N == 1) ? clk :
               (N[0])   ? (clk_p | clk_n) : (clk_p);//其中N==1是判斷不分頻,N[0]是判斷是奇數還是偶數,若為1則是奇數分頻,若是偶數則是偶數分頻。
        
always@(posedge clk or negedge rst_n) begin
if (!rst_n)
    cnt_p <= 0;
else if (cnt_p == (N-1))
    cnt_p <= 0;
else
    cnt_p <= cnt_p + 1;
end

always@(posedge clk or negedge rst_n) begin
if (!rst_n) 
    clk_p <= 1;//此處設置為0也是可以的,這個沒有硬性的要求,不管是取0還是取1結果都是正確的。
else if (cnt_p < (N>>1))/*N整體向右移動一位,最高位補零,其實就是N/2,不過在計算奇數的時候有很明顯的優越性*/
    clk_p <= 1;
else
    clk_p <= 0;    
end

always@(negedge clk or negedge rst_n) begin
if (!rst_n)
    cnt_n <= 0;
else if (cnt_n == (N-1))
    cnt_n <= 0;
else
    cnt_n <= cnt_n + 1;
end

always@(negedge clk or negedge rst_n) begin
if (!rst_n)
    clk_n <= 1;
else if (cnt_n < (N>>1))
    clk_n <= 1;
else
    clk_n <= 0;
end

endmodule




testbench.v

divn_tb.v / Verilog

`timescale 1ns/10ps
module divn_tb;
reg clk;
reg rst_n;
wire o_clk;

divn u0 (
.clk(clk),
.rst_n(rst_n),
.o_clk(o_clk)
);


initial begin
clk   = 1'b1;
rst_n = 1'b1;

   #50 rst_n = 1'b1;/*這一步是一定要加上的,因為,如果不加的話就等於沒有進行初始化,輸出信息是沒有的,這一點已經驗證過了*/
end

// 50MHz clk
always #10 clk = ~clk;
endmodule


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM