1.偶數分頻
簡單,只是注意時鐘翻轉的條件是(N/2)還是(N/2)-1,非阻塞賦值在下一個時鐘纔會更新值。
2.奇數分頻
奇數分頻比偶數分頻複雜一些,當不要求分頻的佔空比時,對輸入時鐘clk上升沿計數,可以設置兩個計數的翻轉點,一個是(N-1)/2,一個是(N-1),計數到(N-1)時輸出時鐘翻轉且將計數器清零,假設計數器計數0~(N-1)/2區間輸出低電平,則輸出時鐘的低電平有(N-1)/2 + 1個clk週期,高電平的計數是(N-1)/2+1 ~ (N-1),共(N-1)/2個clk週期,可見不是50%佔空比。
當要求佔空比爲50%時,對輸入時鐘clk的上升沿和下降沿分別計數,根據兩個計數器得到兩個錯位輸出的時鐘,將兩個時鐘做“或”運算,可以彌補相差的時鐘,達到50%佔空比。
以7分頻爲例,代碼如下:
/********************************************
計數器實現 7 分頻
*********************************************/
module Odd_Divider(
input clk,
input rst_n,
output clk_divider
);
reg [2:0] count_p; //上升沿計數
reg [2:0] count_n; //下降沿計數
reg clk_p; //上升沿分頻
reg clk_n; //下降沿分頻
//上升沿計數
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n )
count_p <= 3'b0;
else if( count_p == 3'd6 )
count_p <= 3'b0;
else
count_p <= count_p + 1'b1;
end
//上升沿分頻
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n ) begin
clk_p <= 1'b0;
end
else begin
if( count_p == 3'd3 || count_p == 3'd6 ) begin
clk_p <= ~clk_p;
end
end
end
//下降沿計數
always @ ( negedge clk or negedge rst_n )
begin
if( !rst_n )
count_n <= 3'b0;
else if( count_n == 3'd6 )
count_n <= 3'b0;
else
count_n <= count_n + 1'b1;
end
//下降沿分頻
always @ ( negedge clk or negedge rst_n )
begin
if( !rst_n ) begin
clk_n <= 1'b0;
end
else begin
if( count_n == 3'd3 || count_n == 3'd6 ) begin
clk_n <= ~clk_n;
end
end
end
assign clk_divider = clk_p | clk_n;
endmodule
仿真如下:
3.小數分頻
N+0.5分頻,如N=3時進行3.5分頻。
先將clk時鐘週期的一半記作clk_half,即一個高電平或一個低電平時間。
對2*(N+0.5) = 2N+1,這個數一定是奇數,按照奇數分頻的思路做,也取clk_p和clk_n,但是計數值不一樣,一個計數N個clk時鐘週期(2N個clk_half週期),一個計數2N+2個clk_half,且兩者的位置關係如圖所示,這樣,兩者做“與”運算,則所得信號一個週期的高低電平共有2N+1個clk_half週期,即(N+0.5)個clk週期。
/********************************************
計數器實現 3.5 分頻,N=3,2N=6
*********************************************/
module Npoint5_Divider(
input clk,
input rst_n,
output clk_divider
);
reg [2:0] count_p; //上升沿計數
reg [2:0] count_n; //下降沿計數
reg clk_p; //上升沿分頻
reg clk_n; //下降沿分頻
//上升沿計數
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n )
count_p <= 3'b0;
else if( count_p == 3'd6 )
count_p <= 3'b0;
else
count_p <= count_p + 1'b1;
end
//上升沿分頻
always @ ( posedge clk or negedge rst_n )
begin
if( !rst_n ) begin
clk_p <= 1'b0;
end
else begin
if( count_p == 3'd4 || count_p == 3'd0 ) begin
clk_p <= ~clk_p;
end
end
end
//下降沿計數
always @ ( negedge clk or negedge rst_n )
begin
if( !rst_n )
count_n <= 3'b0;
else if( count_n == 3'd6 )
count_n <= 3'b0;
else
count_n <= count_n + 1'b1;
end
//下降沿分頻
always @ ( negedge clk or negedge rst_n )
begin
if( !rst_n ) begin
clk_n <= 1'b1;
end
else begin
if( count_n == 3'd4 || count_n == 3'd1 ) begin
clk_n <= ~clk_n;
end
end
end
assign clk_divider = clk_p & clk_n;
endmodule
仿真結果:
歡迎關注:FPGA探索者