分頻器是用的最廣的一種FPGA電路了,我最初使用的是crazybingo的一個任意分頻器,可以實現高精度任意分頻的一個通用模塊,他的思想在于首先指定計數器的位寬比如32位,那么這個計數器的最大值就是2^32=4294967296,
假設系統時鐘為50MHz,那么假如要想實現輸出頻率為fout,那么可以使用的頻率控制字為:
K滿足關系:
,那么設計計數器在每個時鐘上升沿累加的值為K,當計數值為2^31時,clkout=1;否則clkout=0.最終即可以實現任意頻率的輸出,精度的計算方法為當K=1時,可以得到clkout=0.0116415321826934814453125Hz,也即是說可以輸出的最小頻率為0.011Hz
此外我們最為常見的分頻器分為以下4種分析:
1.偶數分頻
最簡單,要想得到分頻系數為N的頻率輸出,設定一個計數器,這個計數器從零開始加1,當加到N/2-1時計數器清零,或者clkout翻轉,以此循環,即可實現偶數倍分頻。
2.奇數分頻(分占空比不確定以及占空比50%)
方法一:分頻系數為N,占總比不確定:以三(N)分頻為例,上升沿觸發計數,計數器計數到1(N-1)/2時輸出時鐘翻轉,計數到2(N-1)時再次翻轉。代碼為產生1/11占空比為十一分頻時鐘:在計數值為9和10時均反轉時鐘,是產生抽樣脈沖的有效方法:
always @(posedge clk or posedge rst) begin
if(rst)begin //復位
cnt《=0;
clk_div11《=0;
end
elseif(cnt==9) begin
clk_div11《=~clk_div11; //時鐘翻轉
cnt《=cnt+1; //繼續計數
end
elseif(cnt==10) begin
clk_div11《=~clk_div11; //時鐘翻轉
cnt《=0; //計數清零
end
else
cnt《=cnt+1;
end
占空比50% ,則可以在上面的基礎上,加上一個下降沿觸發計數,然后將上升沿和下降沿產生的時鐘進行相或運算,即可得到奇數分頻輸出。
reg clk1;
reg[1:0]cnt1;
always@(posedge clk or posedge rst) begin
if(rst)begin //復位
cnt1《=0;
clk1《=0;
end
elseif(cnt1==1) begin
clk1《=~clk1; //時鐘翻轉
cnt1《=cnt1+1; //繼續計數
end
elseif(cnt1==2) begin
clk1《=~clk1; //時鐘翻轉
cnt1《=0; //計數清零
end
else
cnt1《=cnt1+1;
end
reg clk2;
reg[1:0]cnt2;
always@(negedge clk or posedge rst) begin
if(rst)begin //復位
cnt2《=0;
clk2《=0;
end
elseif(cnt2==1) begin
clk2《=~clk2; //時鐘翻轉
cnt2《=cnt2+1; //繼續計數
end
elseif(cnt2==2) begin
clk2《=~clk2; //時鐘翻轉
cnt2《=0; //計數清零
end
else
cnt2《=cnt2+1;
end
assign clk_div3=clk1 | clk2; //或運算
方法二:對進行奇數倍n分頻時鐘,先進行n/2分頻,然后在二分頻得到(這部分先講半整數分頻)
親測有效代碼:
module ModuloN_Cntr(input clk,rst,output clk_out);
reg [1:0]cnt1;
reg [1:0]cnt2;
reg temp1,temp2;
always@(posedge clk or negedge rst)
begin
if(~rst)
begin
cnt1《=0;
temp1《=0;
end
else
begin
if(cnt1==2)
begin
temp1《=1;
cnt1《=0;
end
else
begin
cnt1《=cnt1+1;
temp1《=0;
end
end
end
always@(negedge clk or negedge rst)
begin
if(~rst)
begin
cnt2《=0;
temp2《=0;
end
else
begin
if(cnt2==2)
begin
temp2《=1;
cnt2《=0;
end
else
begin
cnt2《=cnt2+1;
temp2《=0;
end
end
end
assign clk_out=temp1|temp2;
endmodule
仿真波形:
3.半整數分頻
半整數指的是N+0.5分頻器設計:先進行模N+1計數,計數到N時輸出時鐘賦值為1,然后當計數到0時,輸出時鐘賦值為0,因此保持計數值為N的時間為半個時鐘周期即為設計的關鍵,從中可以發現,計數器是在時鐘的上升沿計數,那么我們可以讓時鐘在計數值為N時,將計數觸發時鐘翻轉,時鐘的下降沿變為上升沿,因此計數值為0,所以每產生一個N+0.5分頻時鐘周期,觸發時鐘都要翻轉一次,以2.5分頻為例程序如下:
//異或運算
assignclk_in=clk^clk_div2;
//模3計數器
reg clk_out;
reg [1:0]cnt;
always@(posedge clk_in or posedge rst) begin
if(rst)begin //復位
cnt《=0;
clk_out《=0;
end
elseif(cnt==1) begin
clk_out《=~clk_out; //時鐘翻轉
cnt《=cnt+1; //繼續計數
end
elseif(cnt==2) begin
clk_out《=~clk_out; //時鐘翻轉
cnt《=0; //計數清零
end
else
cnt《=cnt+1;
end
//2分頻
reg clk_div2;
always@(posedge clk_out or posedge rst) begin
if(rst) clk_div2《=0; //復位
else clk_div2=~clk_div2;
end
那么5.5分頻呢:
代碼:通用的這里N=5;
module ModuloN_Cntr(clk,clk_div,temp1,temp2);//N+0.5
input clk;
output clk_div;
reg[31:0]cnt1=0;
reg[31:0]cnt2=0;
output reg temp1,temp2;
initial begin temp1=0;temp2=1;end //首先進行初始化,temp1=0;temp2=1
parameter N=5; //設定分頻系數為N+0.5
always @(posedge clk) //temp1上升沿跳變
begin
if(cnt1==2*N) //2*N
begin cnt1[31:0]《=32‘d0;end
else begin cnt1[31:0]《=cnt1[31:0]+32’d1;end
if(cnt1==32‘d0) begin temp1《=1;end //高電平時間為N+1;
if(cnt1==N+1) begin temp1《=0;end //低電平時間為N;
end
always@(negedge clk) //temp2下降沿跳變
begin
if(cnt2==2*N) //2*N
begin cnt2[31:0]《=32’d0;end
else begin cnt2[31:0]《=cnt2[31:0]+32‘d1;end
if(cnt2==32’d0) begin temp2《=0;end //低電平時間為N;
if(cnt2==N) begin temp2《=1;end //高電平時間為N+1;
end
assign clk_div=temp1&&temp2; //邏輯與
endmodule
//如果要進行N+0.5分頻
//思路:總的來說要進行N+1+N=2N+1次分頻
//在時鐘的上升沿和下降沿都進行跳變
//上升沿進行占空比為N+1比N的時鐘temp1;
//下降沿進行占空比為N比N+1的時鐘temp2;
//最后div=temp1&&temp2 即可得到所需要的半整數分頻
仿真波形:
4.任意小數分頻
小數分頻器的實現方法有很多中,但其基本原理都一樣的,即在若干個分頻周期中采取某種方法使某幾個周期多計或少計一個數,從而在整個計數周期的總體平均意義上獲得一個小數分頻比。一般而言,這種分頻由于分頻輸出的時鐘脈沖抖動很大,故在設計中的使用已經非常少。但是,這也是可以實現的。以8.7倍分頻為例,本文僅僅給出雙模前置小數分頻原理的verilog代碼及其仿真圖(如圖6),具體原理可以參考劉亞海的《基于FPGA的小數分頻器的實現》以及毛為勇的《基于FPGA的任意小數分頻器的設計》。
//8分頻
reg clk_div8;
reg[2:0]cnt_div8;
always@(posedge clk or posedge rst) begin
if(rst)begin //復位
clk_div8《=0;
cnt_div8《=0;
end
elseif(cnt_div8==3‘d7) begin
clk_div8《=1; //置1
cnt_div8《=0;
end
elseif(cnt_div8==3’d0) begin
clk_div8《=0; //置0
cnt_div8《=cnt_div8+1;
end
else
cnt_div8《=cnt_div8+1;
end
//9分頻
reg clk_div9;
reg[3:0]cnt_div9;
always@(posedge clk or posedge rst) begin
if(rst)begin //復位
clk_div9《=0;
cnt_div9《=0;
end
elseif(cnt_div9==3‘d8) begin
clk_div9《=1; //置1
cnt_div9《=0;
end
elseif(cnt_div9==3’d0) begin
clk_div9《=0; //置0
cnt_div9《=cnt_div9+1;
end
else
cnt_div9《=cnt_div9+1;
end
//控制信號
parameterDiv8Num=3;
reg ctrl;
reg[3:0]AddValue;
always@(posedge clk or posedge rst) begin
if(rst)begin //復位
ctrl《=0;
AddValue《=10-7;
end
elseif(AddValue《10) begin
ctrl《=0;
AddValue《=AddValue+Div8Num;
end
else begin
ctrl《=1;
AddValue《=AddValue-10;
end
end
//選擇輸出
reg clk_out;
always @(ctrlor posedge clk or posedge rst) begin
if(rst) clk_out《=0; //復位
elseif(ctrl) clk_out《=clk_div8;
elseclk_out《=clk_div9;
end
4、總結分頻器是FPGA的基礎,而且在FPGA邏輯電路設計的時候是經常使用的,希望大家對以上的整數倍分頻和半整數倍分頻能熟練掌握
原文標題:關于分頻器的FPGA實現整理思路
文章出處:【微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
責任編輯:haq
-
FPGA
+關注
關注
1629文章
21759瀏覽量
604272 -
分頻器
+關注
關注
43文章
447瀏覽量
49987
原文標題:關于分頻器的FPGA實現整理思路
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論