verilog實現奇數倍分頻


在學習FPGA的過程中,最簡單最基本的實驗應該就是分頻器了,
同時分頻器也是FPGA設計中使用頻率非常高的基本設計之一,
盡管在芯片廠家提供的IDE中集成了鎖相環IP
altera 的PLLXilinx ISE的DLL或者vivado中的clock來進行時鍾的分頻,倍頻以及相移。
但是對於時鍾要求不高的邏輯,通過語言進行時鍾的分頻相移顯得十分方便,
這種方法可以節省芯片內部的鎖相環資源,再者,通過語言設計進行時鍾分頻,可以鍛煉我們對verilog的熟練和理解程度。

  • 偶數倍分頻:實現起來比較簡單,這里略過;

  • 奇數倍分頻

    如果不要求占空比為50%的話,也比較容易實現,
    如進行三分頻,通過待分頻時鍾上升沿觸發計數器進行模三計數,
    當計數器計數到鄰近值進行兩次翻轉,比如可以在計數器計數到1時,
    輸出時鍾進行翻轉,計數到2時再次進行翻轉。
    即在計數值在鄰近的1和2進行了兩次翻轉。
    這樣實現的三分頻占空比為1/3或者2/3。

    對於實現占空比為50%的N倍奇數分頻,我們可以分解為兩個通道:

    • 上升沿觸發進行模N計數,計數選定到某一個值進行輸出時鍾翻轉,
      然后經過(N-1)/2再次進行翻轉得到一個占空比為非50%奇數N分頻時鍾
    • 下降沿觸發進行模N計數,到和上升沿觸發輸出時鍾翻轉選定值相同值時,
      進行輸出時鍾時鍾翻轉,同樣經過(N-1)/2時,
      輸出時鍾再次翻轉生成占空比非50%的奇數N分頻時鍾

    將這兩個占空比非50%的N分頻時鍾或運算,得到占空比為50%的奇數n分頻時鍾

    具體例子:5分頻等占空比,可以通過待分頻時鍾下降沿和上升沿觸發0~4計數,

    • 對於待分頻時鍾的上升沿,當計數器cnt1計數到1時,
      clk_p翻轉;當計數器計數到3(1 + (5 - 1) / 2 = 3)時,clk_p再次反轉;
    • 對於待分頻時鍾的下降沿,當計數器cnt2計數到1時,
      clk_n翻轉;當計數器計數到3(1 + (5 - 1) / 2 = 3)時,clk_n再次反轉;
    • 然后下降沿產生的5分頻時鍾和上升沿產生的5分頻時鍾進行運算,
      即可得到占空比為50%的N分頻時鍾。

    這種方法可以實現任意的奇數分頻。

下面給出5分頻的具體代碼:

`timescale 1ns/1ps 

module CLK_DIV5(
    input   clk_i,
    input   rst_n,
    output  clk_o
    );
 
    reg [2:0] cnt1,cnt2;
    reg clk_p,clk_n;
           
//*********************
//MAIN CORE
//*********************        
always @(posedge clk_i,negedge rst_n)
    if(!rst_n) begin
        cnt1 <= 3'b0;
        clk_p <= 1'b0;
    end 
    else begin
        if(cnt1 == 3'b100) begin
            cnt1 <= 3'b0;
            clk_p <= clk_p;
        end
        else begin
            cnt1 <= cnt1 + 1'b1;
            if(cnt1 == 3'b1 || cnt1 == 3'b11)
                clk_p <= ~clk_p;
        end
    end

always @(negedge clk_i,negedge rst_n)
    if(!rst_n) begin
        cnt2 <= 3'b0;
        clk_n <= 1'b0;
    end 
    else begin
        if(cnt2 == 3'b100) begin
            cnt2 <= 3'b0;
            clk_n <= clk_n;
        end
        else begin
            cnt2 <= cnt2 + 1'b1;
            if(cnt2 == 3'b1 || cnt2 == 3'b11)
                clk_n <= ~clk_n;
        end
    end
    
    assign clk_o = clk_p | clk_n;
endmodule

測試激勵模塊:

`timescale 1ns/1ps 

module TB_TOP;

    reg   rst_n  ;
    reg   clk    ;

   CLK_DIV5 U_CLK_DIV5(
        .clk_i(clk),
        .rst_n(rst_n),
        .clk_o(clk_o)
    );
    
//*********************
//MAIN CORE
//*********************        
    initial begin 
        rst_n  =1'b1;
        clk    =1'b0;
        
        #5
        rst_n  = 1'b0;
        #5
        rst_n  = 1'b1;
 
        #500
        $finish;     
    end 
    
    always #1 clk = ~clk;
  
endmodule

modelsim仿真圖:


免責聲明!

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



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