1. 程式人生 > 其它 >verilog奇偶分頻詳解

verilog奇偶分頻詳解

文章目錄


奇偶分頻是一個很常見的問題,這裡探討的分頻都是對於佔空比為50%的訊號分頻,分頻後的訊號也是50%佔空比。分頻原訊號 N N N倍,意味分頻後的訊號的高低電平持續時間是原來訊號的高低電平持續時間的 N N N倍。

偶分頻

原訊號是一個50ns為週期的訊號

在這裡插入圖片描述

在verilog裡面要分頻首先想到的就是用到計數器來對高低電平計數從而產生符合要求分頻訊號,我們目標要產生50%的佔空比的訊號,所以我們可以先不管分頻訊號的低電平的計數,先來看看高電平的計數。

假設用1個計數器來計數,由於在對於暫存器的操作都是以一個週期為單位,意味著無論你的高電平計數為多少,都是以原訊號1個週期為單位計數,同樣無論你的低電平計數為多少,也都是1個週期為單位計數,那麼可以知道高電平持續的時間一定是原訊號高電平持續時間的 2 N 2N

2N倍,低電平持續的時間一定是原訊號低電平持續時間的 2 N 2N 2N倍, N N N代表 N N N個週期,由於產生的分頻訊號是50%的佔空比,所以分頻訊號後低電平和高電平的持續時間相同。

在這裡插入圖片描述

2分頻

module even (
    input clk,
    output reg div_clk = 0
);
    always @(posedge clk) begin
        div_clk <= ~div_clk;
    end
endmodule
`timescale 1ns / 1ps
module tb ();
    
reg clk;
wire div_clk;
 even eventest(
    .clk(clk),
    .div_clk(div_clk)
);
initial begin
    clk = 1;
end
always clk  = #25 ~clk;
endmodule

2分頻甚至都不需要用計數器

在這裡插入圖片描述

2N分頻

module even #
(parameter div_2n = 4)(
    input clk,
    output reg div_clk = 0
);
parameter   width  = $clog2(div_2n);
reg [width-1:0] cnt = 0;  
    always @(posedge clk) begin
        if(cnt  <   div_2n/2-1)
            cnt 		<= cnt + 1'b1;
        else  begin
          	cnt   		<=   0;
          	div_clk 	<= ~div_clk;
        end
    end
endmodule
`timescale 1ns / 1ps
module tb ();
    
reg clk;
wire div_clk;
 even #
 (.div_2n(6)) eventest(
    .clk(clk),
    .div_clk(div_clk)
);
initial begin
    clk = 1;
end
always clk  = #25 ~clk;
endmodule

模擬可以看到確實是6分頻。

在這裡插入圖片描述

奇分頻

同樣我們先只考慮分頻高電平持續時間的情況,前面已經分析過了,對於高電平持續的時間一定是原來訊號高電平持續時間的 2 N 2N 2N倍,而奇分頻要求分頻後的訊號的高電平時間是原來訊號高電平持續時間的奇數倍,那麼分頻後的一個clk做不到,就用兩個clk,先看3分頻

3分頻高電平

如下圖所示我們可以讓clk2相比clk1往後延一個原訊號的高電平時間(25ns),在將clk1與clk2或起來,就能得到相比於原來訊號的高點平(25)3倍的高電平訊號,並且也滿足每個時鐘訊號的高電平是原訊號高電平時間的 2 N 2N 2N倍,這裡的 N N N是1

在這裡插入圖片描述

3分頻低電平

前面已經描述了低電平持續的時間也是1個週期為單位計算,那麼假設讓clk1和clk2的低電平持續時間和高電平持續時間一致。如下圖

在這裡插入圖片描述

那麼得到的分頻訊號clk高電平和低電平持續時間並不相等,不是50%佔空比。沒有達到50%分頻比的要求,這裡可以看到就像是分頻訊號clk的高電平向低電平借了半個週期(原訊號)的持續時間,導致分頻比是75%,但是此時只要在將clk1和clk2的低電平在延續一個週期,那麼clk就可以達到50%佔空比。如下圖

在這裡插入圖片描述

因此為了實現3分頻,低電平需要持續2個時鐘週期,高電平需要持續1個週期,且clk2要相比與clk1延遲半個原訊號週期,在將clk1和clk2或起來就能得到3分頻的分頻訊號。

module odd (
    input clk,
    output div_clk 
);
reg clk1 = 0;
reg clk1_cnt = 0;
wire clk1_num = clk1?1'b0:1'b1;

reg clk2 = 0;
reg clk2_cnt = 0;
wire clk2_num = clk2?1'b0:1'b1;

    always @(posedge clk) begin
        if(clk1_cnt  <  clk1_num)
            clk1_cnt <= clk1_cnt + 1'b1;
        else  begin
            clk1_cnt   <=   0;
            clk1        <= ~clk1;
        end
    end
    always @(negedge clk) begin
        if(clk2_cnt  <  clk2_num)
            clk2_cnt <= clk2_cnt + 1'b1;
        else  begin
            clk2_cnt   <=   0;
            clk2<= ~clk2;
        end
    end
assign div_clk = clk1||clk2;
endmodule
`timescale 1ns / 1ps
module tb ();
    
reg clk;
wire div_clk;
 odd  oddtest(
    .clk(clk),
    .div_clk(div_clk)
);
initial begin
    clk = 1;
end
always clk  = #25 ~clk;
endmodule

在這裡插入圖片描述

一般結果推導

我們唯一能夠控制的就是高低電平的持續時間。
T o 是 原 信 號 的 的 周 期 T o h 是 原 信 號 的 高 電 平 時 間 T o l 是 原 信 號 的 低 電 平 時 間 T o h = T o l T o = 2 T o h = 2 T o l T_o 是原訊號的的週期\\ T_{oh}是原訊號的高電平時間\\ T_{ol}是原訊號的低電平時間\\ T_{oh}=T_{ol}\quad T_o=2T_{oh}=2T_{ol} ToTohTolToh=TolTo=2Toh=2Tol
假設我們控制高電平時間 N h N_h Nh,低電平 N l N_l Nl個時鐘週期,並且將其中一個clk延遲半個原訊號週期與另一個clk的時鐘或起來,能夠得到或後的時鐘
T o r h 或 後 的 時 鍾 高 電 平 持 續 時 間 T o r l 或 後 的 時 鍾 低 電 平 持 續 時 間 T o r h = N h T o + T o h = 2 N h T o h + T o h = ( 2 N h + 1 ) T o h T o r l = N l T o l − T o l = 2 N l T o l − T o l = ( 2 N l − 1 ) T o l T_{orh}或後的時鐘高電平持續時間\\ T_{orl}或後的時鐘低電平持續時間\\ \begin{aligned} T_{orh} &= N_hT_o+T_{oh}\\ &= 2N_hT_{oh}+T_{oh}\\ &= (2N_h+1)T_{oh}\\ T_{orl} &= N_lT_{ol}-T_{ol}\\ &= 2N_lT_{ol}-T_{ol}\\ &= (2N_l-1)T_{ol} \end{aligned} TorhTorlTorhTorl=NhTo+Toh=2NhToh+Toh=(2Nh+1)Toh=NlTolTol=2NlTolTol=(2Nl1)Tol
又因為50%佔空比得到 T o r h = T o r l T o h = T o l T_{orh}=T_{orl}\quad T_{oh}=T_{ol} Torh=TorlToh=Tol,因此
2 N h + 1 = 2 N l − 1 N h = N l − 1 \begin{aligned} 2N_h+1&=2N_l-1\\ N_h &=N_l-1 \end{aligned} 2Nh+1Nh=2Nl1=Nl1
N h = 1 , N l = 2 N_h =1,N_l =2 Nh=1Nl=2是3分頻,當 N h = 2 , N l = 3 N_h =2,N_l =3 Nh=2Nl=3是5分頻。

module odd  #
(parameter div_2n1 = 3)
(
    input clk,
    output div_clk 
);
parameter   width  = $clog2(div_2n1);
reg clk1 = 0;
reg [width-1:0]clk1_cnt = 0;
wire  [width-1:0] clk1_num = clk1?(div_2n1/2-1):div_2n1/2;

reg clk2 = 0;
reg  [width-1:0] clk2_cnt = 0;
wire  [width-1:0] clk2_num = clk2?(div_2n1/2-1):div_2n1/2;

    always @(posedge clk) begin
        if(clk1_cnt  <  clk1_num)
            clk1_cnt <= clk1_cnt + 1'b1;
        else  begin
            clk1_cnt   <=   0;
            clk1        <= ~clk1;
        end
    end
    always @(negedge clk) begin
        if(clk2_cnt  <  clk2_num)
            clk2_cnt <= clk2_cnt + 1'b1;
        else  begin
            clk2_cnt   <=   0;
            clk2<= ~clk2;
        end
    end
assign div_clk = clk1||clk2;
endmodule
`timescale 1ns / 1ps
module tb ();
    
reg clk;
wire div_clk;
 odd  #
    (.div_2n1(5))
 oddtest(
    .clk(clk),
    .div_clk(div_clk)
);
initial begin
    clk = 1;
end
always clk  = #25 ~clk;
endmodule

根據仿真確實是5分頻。
在這裡插入圖片描述