主頁 > 後端開發 > 數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態機分頻|verilog代碼|Testbench|仿真結果)

數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態機分頻|verilog代碼|Testbench|仿真結果)

2023-05-15 07:24:09 後端開發

目錄
  • 一、前言
  • 二、偶數分頻
    • 2.1 觸發器級聯法
    • 2.2 計數器法
    • 2.3 verilog代碼
    • 2.4 Testbench
    • 2.5 仿真結果
  • 三、奇數分頻
    • 3.1 占空比非50%奇數分頻
    • 3.2 占空比50%奇數分頻
    • 3.3 Verilog代碼
    • 3.4 Testbench
    • 3.5 仿真結果
  • 四、小數分頻
    • 4.1 雙模前置分頻法
    • 4.2 Verilog代碼
    • 4.3 Testbench
    • 4.4 仿真結果
  • 五、半整數分頻
    • 5.1 占空比50%半整數分頻
    • 5.2 Verilog代碼
    • 5.3 Testbench
    • 5.4仿真結果
  • 六、狀態機分頻
    • 6.1狀態機分頻
    • 6.2 verilog代碼
    • 6.3 Tsetbench
    • 6.4仿真結果
  • 七、總結

請在此添加圖片描述



數字IC經典電路設計

經典電路設計是數字IC設計里基礎中的基礎,蓋大房子的第一部是打造結實可靠的地基,每一篇筆者都會分門別類給出設計原理、設計方法、verilog代碼、Testbench、仿真波形,然而實際的數字IC設計程序中考慮的問題遠多于此,通過本系列希望大家對數字IC中一些經典電路的設計有初步入門了解,能力有限,紕漏難免,歡迎大家交流指正,

快速導航鏈接如下:

個人主頁鏈接

1.數字分頻器設計

2.序列檢測器設計

3.序列發生器設計

4.序列模三檢測器設計

5.奇偶校驗器設計

6.自然二進制數與格雷碼轉換



一、前言

作為IC設計中經典電路之一,數字分頻器在IC(集成電路)設計中有廣泛的應用,以下是數字分頻器在IC設計中的一些應用:

時鐘發生器:時鐘發生器的原理是時鐘分頻,數字分頻器可以用來將時鐘信號分頻為所需的頻率,例如,如果需要一個1Hz的時鐘信號,可以使用數字分頻器將10Hz的時鐘信號分頻為1Hz,滿足模塊時序要求外還可以達到降低功耗的作用,時鐘發生器是數字系統中非常重要的組件,你就說重不重要!

數字鎖相環(DLL):數字分頻器可以用于數字鎖相環的設計中,以實作時鐘的相位同步,在 IC 設計中,時鐘同步是非常重要的一部分,因為時鐘信號的穩定性和精度直接影響到整個系統的性能和可靠性,數字鎖相環是數字系統中的一種重要的時鐘同步技術之一,你就說重不重要!

數字頻率合成器(DDS):數字分頻器可以用于數字頻率合成器的設計中,以產生所需的頻率,在頻率合成器中,數字分頻器可以用于將高頻信號分頻為多個低頻信號,然后通過DSP進行數字信號處理和合成,最終生成一個高頻信號,雖然分頻只能將高頻分解成低頻信號,但是與DSP結合可以合成高頻信號,可分解高頻信號亦可合成高頻信號,你就說重不重要!

總之,數字分頻器在IC設計中有廣泛的應用,它是數字系統中重要的組件之一,可以實作各種復雜的數字信號處理和時鐘同步技術,它是現代電子技術中不可或缺的一部分,所以掌握數字分頻器的設計是十分重要的!

二、偶數分頻

2.1 觸發器級聯法

采用觸發器反向輸出端連接到輸入端的方式,暫存器級聯法能實作2^N的偶數分頻,具體是采用暫存器結構的電路,每當時鐘上升沿到來的時候輸出結果進行翻轉,以此來實作偶數分頻,

根據以上原理,可實作簡單的 2 分頻電路,以此為基礎進行串聯,可構成 4 分頻和8 分頻電路,電路結構如下圖所示,用 Verilog 描述時只需使用簡單的取反邏輯即可,

請在此添加圖片描述

在此基礎上可畫出2分頻、4分頻、8分頻電路的波形圖(圖由TimeGen繪制,該軟體功能實用,推薦使用),如下圖所示,

請在此添加圖片描述

2分頻設計:只需要使用基準時鐘在第1個時鐘周期輸出高電平(或低電平),在第2個時鐘周期輸出相反電平,

同理,4分頻設計:使用基準時鐘在第1、2個時鐘周期輸出高電平(或低電平),在第3、4個時鐘周期輸出相反電平,

同理,8分頻設計:使用基準時鐘在第1、2、3、4個時鐘周期輸出高電平(或低電平),在第5、6、7、8個時鐘周期輸出相反電平,

2.2 計數器法

如果偶數分頻系數過大或者暫存器級聯法無法實作對應的分頻,可以采用計數器法進行分頻,計數器法可以實作任意偶數分頻,在計數周期達到分頻系數中間數值 (N/2-1) 時進行時鐘翻轉,可保證分頻后時鐘的占空比為 50%,
Tips:中間數值(N/2-1) 需要減1是因為從0開始計數

以六分頻為例,電路需要實作的是:計數器從0開始計數至2,計數器到0時信號翻轉,具體的時序圖如下(圖由TimeGen繪制,該軟體功能實用,推薦使用),

請在此添加圖片描述

因為是偶數分頻,只要對分頻系數中間數值進行回圈計數,在對應的地方讓信號進行反轉即可得到任意分頻的分頻器,

2.3 verilog代碼

//偶數分頻電路設計(2分頻、4分頻、8分頻、6分頻)
//觸發器法實作2分頻、4分頻、8分頻
//計數器法實作6分頻
module clk_div_even(
    input 		rst_n,			//復位信號
    input 		clk,			//源時鐘信號
    output 		clk_div2,		//輸出2分頻
    output 		clk_div4,		//輸出4分頻
    output 		clk_div6,		//輸出6分頻
    output 		clk_div8		//輸出8分頻
    );

//定義4個中間暫存器和1個計數器    
reg         clk_div2_r;
reg 		clk_div4_r;
reg 		clk_div6_r;
reg 		clk_div8_r;
reg [3:0] cnt;

//2分頻時鐘輸出模塊
//源時鐘上升沿觸發,低電平異步復位
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin		//低電平復位
        clk_div2_r <= 1'b0;
    end
    else begin
        clk_div2_r <= ~clk_div2_r;		//源時鐘上升沿信號翻轉得到2分頻時鐘
    end
end

assign clk_div2 = clk_div2_r;		//延時輸出,消除亞穩態

//4分頻時鐘輸出模塊
//2分頻時鐘上升沿觸發 低電平異步復位
always @(posedge clk_div2 or negedge rst_n) begin
    if (!rst_n) begin
        clk_div4_r <= 1'b0;
    end
    else begin
        clk_div4_r <= ~clk_div4_r;		//2分頻時鐘上升沿信號翻轉得到4分頻時鐘
    end
end

assign clk_div4 = clk_div4_r;		//延時輸出,消除亞穩態

//8分頻時鐘輸出模塊
//4分頻時鐘上升沿觸發 低電平異步復位
always @(posedge clk_div4 or negedge rst_n) begin
    if (!rst_n) begin
        clk_div8_r <= 'b0;
    end
    else begin
        clk_div8_r <= ~clk_div8_r;		//4分頻時鐘上升沿信號翻轉得到8分頻時鐘
    end
end
    
assign clk_div8 = clk_div8_r;		//延時輸出,消除亞穩態

//計數器模塊
//源時鐘上升沿觸發,低電平異步復位
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin		//低電平復位
        cnt    <= 4'b0 ;
    end
    else if (cnt == 2) begin		//計數器從0計數,到2清零
        cnt    <= 4'b0 ;
    end
    else begin				//計數累加
        cnt    <= cnt + 1'b1 ;
    end
end

//6分頻時鐘輸出模塊
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin		
        clk_div6_r <= 1'b0;
    end
    else if (cnt == 2 ) begin		//3個周期信號翻轉得到6分頻時鐘
        clk_div6_r <= ~clk_div6_r;
    end
end
    
assign clk_div6 = clk_div6_r;		//延時輸出,消除亞穩態

endmodule

2.4 Testbench

`timescale 1ns/1ns		//時間刻度:單位1ns,精度1ns

module clk_div_even_tb;

//信號申明
 reg 		clk ;
 reg 		rst_n;
 wire 		clk_div2;
 wire 		clk_div4;
 wire 		clk_div6;
 wire 		clk_div8;

//定義源時鐘信號一周期時間
parameter DIV_CLK = 10;

//復位信號生成
initial begin
    clk = 0;		//時鐘信號賦初值
    rst_n = 1;		//復位信號賦初值
    #(1.5*DIV_CLK) rst_n = 0;
    #DIV_CLK rst_n = 1;
    #(30*DIV_CLK);
end

//源時鐘信號生成
always #(DIV_CLK/2) clk = ~ clk;

//模塊例化
clk_div_even u_clk_div_even
    (
    .clk         (clk),
    .rst_n       (rst_n),
    .clk_div2    (clk_div2),
    .clk_div4    (clk_div4),
    .clk_div6    (clk_div6),
    .clk_div8    (clk_div8)
    );

endmodule

2.5 仿真結果

請在此添加圖片描述

三、奇數分頻

3.1 占空比非50%奇數分頻

若要實作N分頻(N為奇數),只需將計數器在待分頻時鐘上升沿觸發回圈計數,計數到0時輸出時鐘翻轉,當計數到(N-1)/2后再次將輸出時鐘翻轉,

以三分頻為例,電路需要實作的是:計數器從0開始計數至2,計數器到0時且在上升沿信號翻轉,計數器到1時且在上升沿信號清零,具體的時序圖如下(圖由TimeGen繪制,該軟體功能實用,推薦使用),

請在此添加圖片描述

3.2 占空比50%奇數分頻

如果對于占空比要求不高的話,只需要簡單地對信號計數并且在對應的計數器位置上升沿觸發信號翻轉即可以得到一個奇數分頻,此奇數分頻往往占空比達不到50%的要求,

那么如何得到一個50%占空比的奇數分頻呢?

從50%占空比奇數分頻波形看,信號的翻轉對應的源時鐘信號分別是上升沿和下降沿,但是雙邊沿觸發在電路設計的時候是不允許的,

那么如何實作這種“類雙邊沿觸發”的效果呢?

對于50%占空比奇數分頻,就是分別利用待分頻時鐘的上升沿觸發生成一個時鐘,然后用下降沿觸發生成另一個時鐘,然后將兩個時鐘信號進行或/與運算得到占空比為50%的奇數分頻,

以三分頻為例,電路需要實作的是:設計2個分別用上升、下降沿觸發的計數器cnt_p和cnt_n,設計2個分別用上升、下降沿觸發的計數器clk_p和clk_n,利用clk_p和clk_n通過或邏輯運算生成占空比為50%的分頻時鐘,具體的時序圖如下(圖由TimeGen繪制,該軟體功能實用,推薦使用),

請在此添加圖片描述

此處我們通過兩個計數器分別對上升沿和下降沿信號進行翻轉,最后通過或運算得到占空比50%的分屏信號,

Tips:此處亦可借用與邏輯運算,對比上面的clk_p和clk_n稍稍不同,大家可以試著自己畫出對應時序圖,

3.3 Verilog代碼

//奇數分頻電路設計(占空比非50%的3分頻和占空比50%的3分頻)
module clk_div_odd (  
    input 		clk,			//時鐘信號
    input 		rst_n,			//復位信號
    output 		clk_div3_1,		//占空比非50%的3分頻時鐘信號輸出
    output 		clk_div3_2		//占空比50%的3分頻時鐘信號輸出
    );

//定義分頻的數目
parameter N = 3;

reg [3:0] 		cnt_p;		//上升沿觸發計數器計數
reg [3:0]		cnt_n;		//下降沿觸發計數器計數
reg       		clk_p;		//上升沿觸發生成的時鐘信號
reg       		clk_n;		//下降沿觸發生成的時鐘信號

//上升沿觸發計數器模塊
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
       cnt_p <= 4'b0000;
    else if (cnt_p == N-1)		//計數器從0計數,到2清零
       cnt_p <= 4'b0000;
    else
       cnt_p <= cnt_p + 1'b1;		//計數器累加
end

//下降沿觸發計數器模塊
always @(negedge clk or negedge rst_n) begin
    if(!rst_n)
       cnt_n <= 4'b0000;
    else if(cnt_n == N-1)		//計數器從0計數,到2清零
      cnt_n <= 4'b0000;
    else
      cnt_n <= cnt_n + 1'b1;		//計數器累加
end

//上升沿觸發生成的時鐘信號模塊
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
       clk_p <= 1'b0;
    else if(cnt_p == (N-1)/2)		//計數器到1且在上升沿,時鐘信號翻轉
       clk_p <= ~clk_p;
    else if (cnt_p <= 0)			//計數器到0且在上升沿,時鐘信號翻轉
       clk_p <= ~clk_p;
    else
       clk_p <= clk_p;				//防止latch產生
end

//下降沿觸發生成的時鐘信號模塊
always @(negedge clk or negedge rst_n)
begin
   if(!rst_n)
      clk_n <= 1'b0;
   else if (cnt_n == (N-1)/2)		//計數器到1且在上升沿,時鐘信號翻轉
      clk_n <= ~clk_n;
   else if (cnt_n == 0)				//計數器到0且在上升沿,時鐘信號翻轉
      clk_n <= ~clk_n;
   else
      clk_n <= clk_n;				//防止latch產生
end

//延時輸出,消除亞穩態
assign clk_div3_1 = clk_p;				//得到占空比非50%的3分頻時鐘信號
assign clk_div3_2 = clk_p | clk_n;		//或邏輯運算得到占空比50%的3分頻時鐘信號

endmodule

3.4 Testbench

`timescale 1ns/1ps		//時間刻度:單位1ns,精度1ps
module clk_div_odd_tb;

//信號申明
reg clk;
reg rst_n;
wire clk_div3_1;		//占空比非50%的3分頻時鐘信號
wire clk_div3_2;		//占空比50%的3分頻時鐘信號

parameter DIV_CLK = 5;		//定義源時鐘信號一周期時間

//復位信號生成
initial begin
	clk = 0;		//時鐘信號賦初值
    rst_n = 1;		//復位信號賦初值
	#(3*DIV_CLK)
	rst_n = 0;
	#(6*DIV_CLK)
	rst_n = 1;
	#(20*DIV_CLK);
end

//源時鐘信號生成
always #DIV_CLK clk = ~clk;

//模塊例化
clk_div_odd u_clk_div_odd
    (.clk           (clk),
     .rst_n         (rst_n),
     .clk_div3_1    (clk_div3_1),
     .clk_div3_2    (clk_div3_2)
    );

endmodule

3.5 仿真結果

請在此添加圖片描述

四、小數分頻

4.1 雙模前置分頻法

不規整的小數分頻不能做到分頻后的每個時鐘周期都是源時鐘周期的小數分頻倍,更不能做到分頻后的時鐘占空比均為 50%,因為 Verilog 不能對時鐘進行小數計數,

小數分頻是基于可變分頻和多次平均的方法實作的,

例如進行5.4倍分頻,則保證源時鐘54個周期的時間等于分頻時 10個周期的時間即可,此時需要在54個源時鐘周期內進行6次5分頻,4次6分頻,

T = ( Ma+(M+1)b )/ a+b,這里我們發現組成小數分頻使用了a個M分頻和b個M+1分頻的整數分頻電路,

以 5.4 倍分頻為例:

基本思想是在54個源時鐘周期里完成10個5.4分頻,根據前面的公式可知:有6的5分頻和4個6分頻,只要將5分頻和6分頻插入在54個源時鐘周期即可,

同時我們應當考慮分頻信號的實作順序

5分頻和6分頻的實作順序一般有以下 4 種:

(1)先進行 6 次 5 分頻,再進行 4 次 6 分頻;

(2) 先進行 4 次 6分頻,再進行 6 次 5 分頻;

(3) 將 6 次 5 分頻平均的插入到 4 次 6 分頻中;

(4) 將 4 次 6 分頻平均的插入到 6 次 5 分頻中,

前兩種方法時鐘頻率不均勻,相位抖動較大,所以一般會采用后兩種平均插入的方法進行小數分頻操作,

那又如何平均插入呢?

平均插入可以通過分頻次數差累計的方法實作,5.4 分頻的實作程序如下:

(1) 第一次分頻次數差值 54 - 10×5 = 4 < 10,第一次進行 5 分頻,

(2) 第二次差值累加結果為 4+4=8 < 10,第二次使用 5 分頻,同時差值修改為(54-10×5) + (54 -10×5) = 8 ,

(3) 第三次差值累加結果為 4 + 8 = 12 > 10,第三次使用 6分頻,

(4) 第四次差值累加結果為 12 + (54-10×6) < 10,第四次使用 5 分頻,

以此類推,完成將 6 次 5分頻平均插入到 4 次 6分頻的程序

具體的時序圖如下(圖由TimeGen繪制,該軟體功能實用,推薦使用),此時相位抖動相對較小,

Tips:每一段并不是嚴格的5.4分頻(因為信號翻轉只在邊沿觸發),而是在54個源時鐘周期平均下來有10個分頻,而且時序難以保證,且占空比幾乎達不到50%,

請在此添加圖片描述

4.2 Verilog代碼

//小數分頻電路設計
//雙模前置法實作5.4分頻
module clk_div_fraction
   (
    input				rst_n,		//復位信號
    input               clk,		//時鐘信號
    output              clk_frac	//小數分頻輸出信號
    );
 
 //定義介于5.4分頻的5分頻和6分頻
parameter		CLK_DIV_1  =  5;
parameter    	CLK_DIV_2  =  6;
parameter    	DIFF       =  4;		//10個周期內5分頻與5.4分頻的差值


reg [3:0]            cnt_end;			//分頻插入計數器	(用于判斷插入什么分頻)	
reg [3:0]            cnt;				//總計數器
reg                  clk_frac_r; 		//小數分頻中間暫存器信號
reg [4:0]            diff_cnt_r;		//差值信號
reg [4:0]            diff_cnt;			//差值信號
wire                 diff_cnt_en= cnt == cnt_end;		//使能信號

//差值累加邏輯模塊
always @(*) begin
    if(diff_cnt_r >= 10) begin
        diff_cnt = diff_cnt_r -10 + DIFF;	//差值大于10,插入6分頻,差值減6
    end
    else begin
        diff_cnt = diff_cnt_r + DIFF;		//差值小于10,插入5分頻,差值加4
    end
end
  
// 借用暫存器延遲輸出diff_cnt_r                           
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin				//復位差值清零
        diff_cnt_r <= 0;
    end
    else if(diff_cnt_en) begin		//使能信號高電平時,差值信號延遲輸出
        diff_cnt_r <= diff_cnt;
    end
end

//5分頻和6分頻插入邏輯模塊
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt_end <= CLK_DIV_1-1 ;		//復位先插入5分頻
    end
    else if(diff_cnt >= 10) begin
        cnt_end <= CLK_DIV_2-1 ;		//差值大于10,插入6分頻
    end
    else begin
        cnt_end <= CLK_DIV_1-1 ;		//差值小于10,插入5分頻
    end
end

//
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin					//總計數器、分頻信號信號復位
        cnt <= 1'b0;
        clk_frac_r <= 1'b0;
    end
    else if(cnt == cnt_end) begin		//計數器到分頻插入界限點
        cnt <= 1'b0;					//總計數器清零
        clk_frac_r <= 1'b1;				//時鐘分頻信號電平置"1"
    end
    else begin			//其他情況下,計數器累加計數、時鐘分頻信號電平保持"0"
        cnt <= cnt + 1'b1;		
        clk_frac_r <= 1'b0;
    end
end

//延時輸出,消除亞穩態  
assign clk_frac = clk_frac_r;

endmodule

4.3 Testbench

`timescale 1ns/1ps		//時間刻度:單位1ns,精度1ps
module clk_div_fraction_tb;

//信號申明
reg			clk;				
reg			rst_n;
wire		clk_frac;			

parameter DIV_CLK = 5;			//定義源時鐘信號一周期時間

//復位信號生成 
initial begin
    clk = 0;			//時鐘信號賦初值
	rst_n = 1;			//復位信號賦初值
	#(3*DIV_CLK)
	rst_n = 0;
	#(6*DIV_CLK)
	rst_n = 1;
	#(20*DIV_CLK);
end

//源時鐘信號生成
always #DIV_CLK clk = ~clk;

//模塊例化
clk_div_fraction u_clk_div_fraction
    (.clk             (clk),
     .rst_n           (rst_n),
     .clk_frac        (clk_frac)
    );

endmodule

4.4 仿真結果

請在此添加圖片描述

請在此添加圖片描述

把5.4小數分頻和2.6小數分頻進行比較,圖一是5.4小數分頻仿真時序圖,可以看到波形較為整齊;圖二是2.6小數分頻仿真時序圖,可以看到波形較為雜亂;

Tips:5.4小數分頻并不是每一段都是均勻的長度(即區域不滿足小數分頻,總體滿足小數分頻)

那么是什么原因造成的呢?

從前面的基本原理可以知道,通過雙模前置法得到的小數分頻波形是差強人意的,5.4小數分頻通過5分頻和6分頻差值得到,2.6小數分頻通過2分頻和3分頻差值得到,同樣差一個cnt,對于2.6小數分頻的波形破壞要比5.4小數分頻要嚴重,總而言之就是:區域不滿足小數分頻,總體滿足小數分頻,

五、半整數分頻

5.1 占空比50%半整數分頻

對于使用小數分頻法得到的,以3.5分頻為例,需要使用一個四分頻和一個三分頻,七個周期內,輸出兩個1,但是信號時序難以得到保障,時鐘信號的質量得不到保證,

那有沒有新的方法可以優化半整數分頻呢?

可以這樣實作半整數分頻:
(1)在源時鐘上升沿分別產生由 4 個和 3 個源時鐘周期組成的 2 個分頻時鐘,

(2)在源時鐘下降沿分別產生由 4 個和 3 個源時鐘周期組成的 2 個分頻時鐘,

(3)兩個分頻時鐘做相位一個延遲半個源時鐘周期,一個提前半個源時鐘周期,將兩次產生的時鐘進行“或”操作,便可以得到周期均勻的 3.5 倍分頻時鐘,分頻波形示意圖如下所示,

請在此添加圖片描述

5.2 Verilog代碼

//半整數分頻電路設計
module clk_div_half
    (
    input               rst_n,
    input               clk,
    output              clk_div
    );

parameter            DIV_CLK = 7;			//3.5分頻的高低電平總個數
reg [3:0]            cnt;					//總計數器
reg                  clk_p;					//上升沿觸發生成的時鐘信號
reg                  clk_n;					//下降沿觸發生成的時鐘信號

//計數器模塊
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt <= 1'b0 ;
     end
     else if (cnt == DIV_CLK-1) begin 		//從0計數,到6清零
        cnt <= 'b0 ;
     end
     else begin
         cnt <= cnt + 1'b1 ;
     end
end

//上升沿觸發生成的時鐘信號模塊
//計數器到0和4并且在上升沿觸發信號翻轉
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
          clk_p <= 1'b0;
     end
      else if (cnt == 0) begin					//計數器到0信號翻轉
          clk_p <= 1;
      end
      else if (cnt == (DIV_CLK/2)+1) begin		//計數器到4信號翻轉
          clk_p <= 1 ;
      end
      else begin
          clk_p <= 0 ;
      end 
end

//下降沿觸發生成的時鐘信號模塊
//計數器到1和4并且在下降沿觸發信號翻轉
always@(negedge clk or negedge rst_n) begin
    if(!rst_n) begin
         clk_n <= 1'b0 ;
    end
    else if(cnt == 1) begin						//計數器到1信號翻轉
         clk_n <= 1 ;
    end
    else if (cnt == (DIV_CLK/2)+1 ) begin		//計數器到4信號翻轉
         clk_n<= 1 ;
    end
    else begin
         clk_n <= 0 ;
    end
end

//或邏輯運算得到占空比50%的3.5半整數分頻信號
assign clk_div = clk_p | clk_n;

endmodule

5.3 Testbench

`timescale 1ns/1ps			//時間刻度:單位1ns,精度1ps
module clk_div_half_tb;

//信號申明
reg 			clk;
reg 			rst_n;
wire 			clk_div;
  
parameter DIV_CLK0 = 5;		//定義源時鐘信號一周期時間

//復位信號生成 
initial begin
    clk = 0;				//時鐘信號賦初值
	rst_n = 1;				//復位信號賦初值
	#(3*DIV_CLK0)
	rst_n = 0;
	#(6*DIV_CLK0)
	rst_n = 1;
	#(20*DIV_CLK0);
end

//源時鐘信號生成
always #DIV_CLK0 clk = ~clk;

//模塊例化
clk_div_half u_clk_div_half
    (.clk             (clk),
     .rst_n           (rst_n),
     .clk_div         (clk_div)
    );

endmodule

5.4仿真結果

請在此添加圖片描述

六、狀態機分頻

6.1狀態機分頻

Verilog 中狀態機主要用于同步時序邏輯的設計,能夠在有限個狀態之間按一定要求和規律切換時序電路的狀態,狀態的切換方向不但取決于各個輸入值,還取決于當前所在狀態,狀態機可分為 2 類:Moore 狀態機和 Mealy 狀態機,

例如完成一個四分頻且占空比為25%的分頻器,此時可以列出四種狀態,狀態機在四種狀態不斷切換,根據下一個輸出狀態只與當前狀態有關而與輸出無關,可以知道此分頻器可根據Moore狀態機完成,

請在此添加圖片描述

6.2 verilog代碼

module clk_div_FSM
    (
    input wire clk,
    input wire rst_n,
    output reg clk_FSM
    );

//定義四種狀態 
parameter	S0 = 2'b00;
parameter	S1 = 2'b01;
parameter	S2 = 2'b10;
parameter	S3 = 2'b11;
 
reg [1:0]	state;			//定義目前狀態
reg [1:0]	next_state;		//下一狀態

//信號復位模塊
always @(posedge clk,negedge rst_n) begin
    if(!rst_n) begin 
        state <= S0;
    end
    else begin
        state <= next_state;
    end
end

//狀態轉換模塊(相當于用狀態機寫計數器)
always @(*) begin
    case (state)
        S0:	next_state = S1;
        S1:	next_state = S2;
        S2:	next_state = S3;
        S3:	next_state = S0;
    endcase
end

//信號輸出模塊
always @(*) begin
    if(state == S0) begin
        clk_FSM = 1'b1;
    end
    else begin
        clk_FSM = 1'b0;
    end
end

endmodule

6.3 Tsetbench

`timescale 1ns/1ps
module clk_div_FSM_tb;

//信號申明
reg				 clk;
reg 			 rst_n;
wire			 clk_FSM;

parameter DIV_CLK = 5;			//定義源時鐘信號一周期時間

//復位信號生成 
initial begin
    clk = 0;				//時鐘信號賦初值
    rst_n = 1;				//復位信號賦初值
    #(3*DIV_CLK)
    rst_n = 0;
    #(6*DIV_CLK)
    rst_n = 1;
    #(20*DIV_CLK);
end

//源時鐘信號生成
always	#DIV_CLK clk = ~clk;

//模塊例化
clk_div_FSM u_clk_div_FSM
    (.clk             (clk),
     .rst_n           (rst_n),
     .clk_FSM         (clk_FSM)
    );

endmodule

6.4仿真結果

請在此添加圖片描述

七、總結

偶數分頻:無論是通過D觸發器還是計數器實作,這類分頻都是最容易得到的,并且占空比容易控制在50%,對于D觸發器實作偶數分頻來說,分頻數只能得2^n,其余分頻數只能由計數器法等其他方法實作,除此以外,隨著分頻的數目不斷增大,通過D觸發器實作觸發器數目會增多,在電路設計的程序中應當考慮面積因素,對于計數器實作偶數分頻,占空比和分頻數都可以得到極大的控制,是實作偶數分頻最靈活的一種方式,

奇數分頻:計數分頻基本原理也是通過計數器實作的,主要分為占空比非50%的奇數分頻和占空比50%的奇數分頻,后者實作簡單而后者稍稍復雜一些,占空比非50%的情況下,時鐘信號在上升沿(N-1)/2翻轉和 0翻轉即可得到需要的分頻信號,占空比50%的情況下,一個時鐘信號在上升沿而一個時鐘信號在下降沿,觸發(N-1)/2翻轉和0翻轉,然后將clk_p和clk_n做或邏輯運算即可得到占空比50%的計數分頻信號,從以上可以看出,占空比50%的奇數分頻只是在占空比非50%的奇數分頻的基礎上多做了一個邏輯運算,

小數分頻:目前小數分頻使用較多的方法是雙模前置分頻法,基本原理是在小數分頻的兩側尋找相近的分頻去插入,營造在一定的源時鐘周期走過與小數分頻相當的的時鐘周期,但是往往分頻的時序波形比較亂,占空比幾乎達不到50%,效果差強人意,究其根本原因是信號只在源時鐘的邊沿觸發,

半整數分頻:半整數分頻是小數分頻的特殊情況,之所以會拎出來單獨講,是因為根據小數分頻的雙模前置法做出來的波形時序較差,如果需要得50%的半整數分頻怎么辦? 首先做出兩個上升沿下降沿二分頻信號,通過在半整數兩邊尋找相鄰的的奇數和偶數(決定信號電平周期數),然后做邏輯運算即可以得到占空比50%的半整數分頻,

狀態機分頻:可以實作分頻的方式之一,對于簡單的分頻器可以采用狀態機來實作,大部分情況狀態機用來處理較為復雜的情況與問題,在分頻電路里有大材小用的感覺,電路分頻時可以采用更簡單的計數器代替狀態機的狀態轉換,

不定期檢查、補充、糾錯,歡迎隨時交流糾錯

最后修改日期:2023.5.10

軟體版本:

  • 仿真軟體:Modelsim 10.6c
  • 時序繪制軟體:TimeGen 3.2
  • 描述語言:verilog

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552414.html

標籤:其他

上一篇:數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態機分頻|verilog代碼|Testbench|仿真結果)

下一篇:返回列表

標籤雲
其他(159008) Python(38129) JavaScript(25421) Java(18034) C(15226) 區塊鏈(8265) C#(7972) AI(7469) 爪哇(7425) MySQL(7184) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4572) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1972) 功能(1967) Web開發(1951) HtmlCss(1936) python-3.x(1918) C++(1915) 弹簧靴(1913) xml(1889) PostgreSQL(1876) .NETCore(1860) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • 數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態

    偶數分頻:無論是通過D觸發器還是計數器實作,這類分頻都是最容易得到的,并且占空比容易控制在50%。對于D觸發器實作偶數分頻來說,分頻數只能得2^n,其余分頻數只能由計數器法等其他方法實作。除此以外,隨著分頻的數目不斷增大,通過D觸發器實作觸發器數目會增多,在電路設計的程序中應當考慮面積因素。對于計數... ......

    uj5u.com 2023-05-15 07:24:09 more
  • 數字分頻器設計(偶數分頻、奇數分頻、小數分頻、半整數分頻、狀態

    偶數分頻:無論是通過D觸發器還是計數器實作,這類分頻都是最容易得到的,并且占空比容易控制在50%。對于D觸發器實作偶數分頻來說,分頻數只能得2^n,其余分頻數只能由計數器法等其他方法實作。除此以外,隨著分頻的數目不斷增大,通過D觸發器實作觸發器數目會增多,在電路設計的程序中應當考慮面積因素。對于計數... ......

    uj5u.com 2023-05-15 07:22:13 more
  • R語言資料繪圖學習(0x01)-安裝ggplot2與嘗試

    0x01 安裝與R基礎 一直聽說資料分析里R語言是比較‘正統’,況且久聞ggplot2這些R語言的資料分析庫大名,想到今后資料分析和整理的需要,這里開一個簡單的系列學習一些R語言和ggplot2的繪圖基礎。本人學習的書籍是Winston Chang大佬的《R Graphics Cookbook》,且 ......

    uj5u.com 2023-05-13 07:41:55 more
  • python高級技術(行程二)

    一 行程物件及其他方法 '''一臺計算機上面運行著很多行程,那么計算機是如何區分并管理這些行程服務端的呢?計算機會給每一個運行的行程分配一個PID號如何查看 windows電腦 進入cmd輸入tasklist即可查看 tasklist|findstr PID查看具體的行程 linux電腦 進入終端之 ......

    uj5u.com 2023-05-13 07:36:35 more
  • 使用 IDEA 時突然斷電導致 git 本地分支損壞的解決方案

    使用IDEA提交專案的時候突然斷電,重啟后專案 git 損壞,所有檔案變成了 untracked,IDEA 界面上表示為所有檔案名變成綠色,并且無法 pull (也可能是無法 push) 提示 Git Pull Failed From http://***************** * branc ......

    uj5u.com 2023-05-13 07:24:33 more
  • Spring AOP 分享

    初級篇 AOP是什么? Aspect-oriented Programming (AOP) 即面向切面編程。簡單來說,AOP 是一種編程范式,允許我們模塊化地定義橫跨多個物件的行為。AOP 可以幫助我們將應用程式的關注點分離,使得代碼更加清晰、易于維護和擴展。 大白話:在方法執行前后運行指定代碼,比 ......

    uj5u.com 2023-05-13 07:22:03 more
  • 閱讀論文的方法和技巧(快速且有效)

    如何從一個小白快速開始入手看論文,然后看論文,發論文。請仔細看下面的講解。歡迎大家一起交流和補充。 閱讀論文的方法和技巧 一.閱讀論文五個重要步驟(通常用時30-60分鐘) 1.第一遍是快速瀏覽論文的摘要、結論、框架圖,有助于把握核心,對論文的內容形成整體感知。(5-10分鐘) 當然,這一遍建議在網 ......

    uj5u.com 2023-05-12 10:48:00 more
  • Java的列舉型別

    如果類的物件的數量只有有限個,并且可以確定物件的屬性,那么考慮使用列舉類。所有的列舉型別都是 Enum 類的子類。它們繼承了這個類的許多方法。 ......

    uj5u.com 2023-05-12 10:47:56 more
  • 閱讀論文的方法和技巧(快速且有效)

    如何從一個小白快速開始入手看論文,然后看論文,發論文。請仔細看下面的講解。歡迎大家一起交流和補充。 閱讀論文的方法和技巧 一.閱讀論文五個重要步驟(通常用時30-60分鐘) 1.第一遍是快速瀏覽論文的摘要、結論、框架圖,有助于把握核心,對論文的內容形成整體感知。(5-10分鐘) 當然,這一遍建議在網 ......

    uj5u.com 2023-05-12 10:47:13 more
  • Java的列舉型別

    如果類的物件的數量只有有限個,并且可以確定物件的屬性,那么考慮使用列舉類。所有的列舉型別都是 Enum 類的子類。它們繼承了這個類的許多方法。 ......

    uj5u.com 2023-05-12 10:46:48 more