奇分频和偶分频
奇分頻和偶分頻
前言
在數字電路中,時鐘占據著重要的作用,在FPGA的開發中,都是以時鐘為基本單位來計算時間的,一般在我們使用的FPGA開發板中,只有一個晶振用來產生時鐘。因此,在開發板設計好之后,只能有一個頻率的時鐘,但是我們在實際開發的過程過,使用的時鐘遠遠不止一個,這個時候就需要我們產生新的時鐘。通常稱為分頻和倍頻,產生分頻有兩種方式:使用PLL核和verilog代碼自己實現;而倍頻我們只能通過PLL核來實現;分頻總體上可以分為偶分頻、奇分頻和小數分頻三種,在本文中將為大家介紹如何通過verilog自己實現占空比為50%的奇偶分頻。
偶分頻
首先以一個四分頻為例來向大家講解。
在開始之前,為了便于理解,首先在這里提供一個圖(手繪的,不太標準,但是意思能表達出來):
假設原來的時鐘為clk,四分頻之后的時鐘為clk_4,則四分頻就是把原來的四個時鐘周期變成現在的一個時鐘周期。我們假設一個計數器為div_cnt,初始值為0,每來一個clk的上升沿,就給div_cnt加1,則當div_cnt = 3時,正好來了4個clk(因為div_cnt的值是從0開始加的,所以從0到3計數值為4),正好構成了一個clk_4,然后讓div_cnt又從0開始計數,產生下一個clk_4。
因為我們要產生一個占空比為50%的四分頻,所以現在考慮什么時候是clk_4的上升沿,什么時候是下降沿。我們任然從div_cnt這個計數器來考慮,因為div_cnt的值為0、1、2、3,當為3時正好是clk_4的一個時鐘周期。又因為占空比為50%,所以clk_4的高電平和低電平各占一半,對應到div_cnt上,可以設定為clk_4的低電平部分對應的是div_cnt 的0和1,clk_4的高電平對應的是div_cnt的2和3。
四分頻的div_cnt的變化是從0到3,分頻之后的時鐘clk_4由低電平變為高電平是在div_cnt為1的時刻,我們用上面同樣的方式分析,可以知道,當為六分頻時,div_cnt的變換是從0到5,分頻之后的時鐘由低電平變為高電平是在div_cnt為3的時刻。
當我們要產生任意偶分頻時,我們假設分頻系數為DIV_CLK_FACTOR,也就是我們要幾分頻,計數器仍然為div_cnt,并且div_cnt的初始值為0?;谏厦娴姆治?#xff0c;可以知道,當div_cnt計數到DIV_CLK_FACTOR-1時,恰好是我們所需要的時鐘的一個周期,并且div_cnt為(DIV_CLK_FACTOR/2)-1時,為分頻之后的時鐘由低電平變為高電平的時刻。
下面使用verilog來實現任意偶分頻:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2020 All rights reserved // ----------------------------------------------------------------------------- // Author : lvdongtao tdlv@stu.xidian.edu.cn // File : even_div_clk.v // Create : 2020-12-02 15:18:19 // Editor : sublime text3, tab size (4) // Description : 實現任意的偶數分頻,占空比為50% // ----------------------------------------------------------------------------- module even_div_clk (input wire sclk,input wire rst_n,output reg div_clk );parameter DIV_CLK_FACTOR = 4; //分頻系數,表示需要幾分頻,這里以4分頻為例reg [15:0] div_cnt; //分頻計數器,根據分頻系數來確定,這里我給的稍大一點//分頻計數器計數 always @(posedge sclk)beginif(!rst_n)begindiv_cnt <= 16'd0;endelse beginif(div_cnt == DIV_CLK_FACTOR - 1)div_cnt <= 'd0;else div_cnt <= div_cnt + 1'b1;end end//分頻 always @(posedge sclk)beginif(!rst_n)begindiv_clk <= 1'b0;endelse beginif(div_cnt == DIV_CLK_FACTOR/2-1)div_clk <= 1'b1;else if(div_cnt == DIV_CLK_FACTOR - 1)div_clk <= 1'b0;else div_clk <= div_clk;end endendmodule測試激勵:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2020 All rights reserved // ----------------------------------------------------------------------------- // Author : lvdongtao tdlv@stu.xidian.edu.cn // File : tb_even_div_clk.v // Create : 2020-12-02 15:28:22 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- `timescale 1ns/1ns module tb_even_div_clk();reg sclk; reg rst_n; wire div_clk;initial beginsclk = 0;rst_n = 0;#100rst_n = 1; end always #10 sclk = ~sclk;even_div_clk even_div_clk_inst (.sclk(sclk), .rst_n(rst_n), .div_clk(div_clk) );endmodule對應的仿真結果:
當把DIV_CLK_FACTOR的值改成16,進行16分頻時,對應的仿真結果:
奇分頻
相對偶分頻而言,要實現占空比為50%的奇分頻要復雜一點,同樣以一個圖開始:
首先我們只看圖中的clk和clk_5兩個信號(這里我們約定clk和clk_5以低脈沖開始)。其中clk是原始時鐘,clk_5為5分頻后的時鐘,對比兩個圖可以看到,clk_5的一個周期剛好是clk的五個時鐘周期,并且clk_5由低變高是時刻是clk的第2.5個時鐘周期處,也就是第2個時鐘周期結束后,占了第3個周期的一半,然后變為了高電平。在此,我們確定了clk_5的高脈沖和低脈沖到來的時刻,接下來確定計數器的計數情況。如果使用一個計數器來進行控制的話,不可能實現,因為不管是使用clk的上升沿控制計數器還是下降沿控制計數器,每次clk的一個周期,計數器才計數一次,不可能讓計數器在半個周期中計數一次。因此,考慮使用兩個計數器。
其中,一個計數器由clk的上升沿驅動,另一個計數器由clk的下降沿驅動,也就是圖中的pos_cnt和neg_cnt,每來一個clk的上升沿,就給pos_clk加1,每來一個clk的下降沿就給neg_cnt加1,并且這兩個計數器計數范圍都是0到4?,F在我們看圖中的clk、clk_5、pos_cnt、neg_clk這四個信號,我們可以看到當pos_cnt計數到2時,正好clk_5的上升沿到來,當neg_cnt計數到4時,正好clk_5的下降沿到來。
因為使用兩個計數器,因此我們也考慮使用兩個中間時鐘來控制。其中一個和clk的上升沿有關,另一個和clk的下降沿有關,也就是對應圖中的pos_clk和neg_clk,在得到兩個中間時鐘之后,通過觀察可以 發現,將pos_clk和neg_clk進行或運算即可得到clk_5。
同理,我們假設分頻系數為DIV_CLK_FACTOR,則定義pos_cnt和neg_cnt的變化范圍都是DIV_CLK_FACTOR-1,并且兩個中間時鐘pos_clk和neg_clk是在兩個計數器值為DIV_CLK_FACTOR/2 - 1時分別從低變高,在兩個計數器值為DIV_CLK_FACTOR - 1時分別從高變低,然后將兩個時鐘進行或運算。
下面使用verilog代碼實現:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2020 All rights reserved // ----------------------------------------------------------------------------- // Author : lvdongtao tdlv@stu.xidian.edu.cn // File : odd_div_clk.v // Create : 2020-12-02 15:38:10 // Editor : sublime text3, tab size (4) // Description: 實現任意的奇數分頻,占空比為50% // ----------------------------------------------------------------------------- module odd_div_clk(input wire sclk,input wire rst_n,output wire div_clk );parameter DIV_CLK_FACTOR = 5; //分頻系數,表示需要幾分頻reg [15:0] pos_cnt;//分頻計數器,根據分頻系數來確定,這里我給的稍大一點 reg [15:0] neg_cnt;//分頻計數器,根據分頻系數來確定,這里我給的稍大一點reg pos_clk; reg neg_clk;always @(posedge sclk)beginif(!rst_n)beginpos_cnt <= 16'd0;endelse beginif(pos_cnt == DIV_CLK_FACTOR - 1)pos_cnt <= 'd0;else pos_cnt <= pos_cnt + 1'b1;end endalways @(posedge sclk) beginif (!rst_n) beginpos_clk <= 1'b0; endelse beginif(pos_cnt == DIV_CLK_FACTOR / 2)pos_clk <= 1'b1;else if(pos_cnt == DIV_CLK_FACTOR - 1)pos_clk <= 1'b0;else pos_clk <= pos_clk;end endalways @(negedge sclk)beginif(!rst_n)beginneg_cnt <= 16'd0;endelse beginif(pos_cnt == DIV_CLK_FACTOR - 1)neg_cnt <= 'd0;else neg_cnt <= neg_cnt + 1'b1;end end always @(negedge sclk)beginif(!rst_n)beginneg_clk <= 1'b0;endelse beginif(neg_cnt == DIV_CLK_FACTOR / 2)neg_clk <= 1'b1;else if(neg_cnt == DIV_CLK_FACTOR - 1)neg_clk <= 1'b0;else neg_clk <= neg_clk;end endassign div_clk = pos_clk | neg_clk;endmodule測試激勵:
// ----------------------------------------------------------------------------- // Copyright (c) 2014-2020 All rights reserved // ----------------------------------------------------------------------------- // Author : lvdongtao tdlv@stu.xidian.edu.cn // File : tb_odd_div_clk.v // Create : 2020-12-02 15:49:15 // Editor : sublime text3, tab size (4) // ----------------------------------------------------------------------------- `timescale 1ns/1ns module tb_odd_div_clk();reg sclk; reg rst_n; wire div_clk; initial beginsclk = 0;rst_n = 0;#100rst_n = 1; endalways #10 sclk = ~sclk;odd_div_clk inst_odd_div_clk (.sclk(sclk), .rst_n(rst_n), .div_clk(div_clk) );endmodule仿真結果:
當DIV_CLK_FACTOR的值改成15,進行15分頻時,對應的仿真結果:
在下一篇文章將向大家講解如何實現占空比為50%的任意整數分頻。
總結
- 上一篇: DDS发生器的verilog实现(三)
- 下一篇: 黄仕沛经方医案医话精选(上) 王晓军