時鐘訊號的處理是fpga的特色之一,因此分頻器也是fpga設計中使用頻率非常高的基本設計之一。一般在fpga中都有整合的鎖相環可以實現各種時鐘的分頻和倍頻設計,但是通過語言設計進行時鐘分頻是最基本的訓練,在對時鐘要求不高的設計時也能節省鎖相環資源。在本實驗中我們將實現任意整數的分頻器,分頻的時鐘保持50%占空比。
1,偶數分頻:偶數倍分頻相對簡單,比較容易理解。通過計數器計數是完全可以實現的。如進行n倍偶數分頻,那麼通過時鐘觸發計數器計數,當計數器從0計數到n/2-1時,輸出時鐘進行翻轉,以此迴圈下去。
總結如下:對於實現占空比為50%的n倍奇數分頻,首先進行上公升沿觸發進行模n計數,計數選定到某乙個值進行輸出時鐘翻轉,然後經過(n-1)/2再次進行翻轉得到乙個占空比非50%奇數n分頻時鐘。再者同時進行下降沿觸發的模n計數,到和上公升沿觸發輸出時鐘翻轉選定值相同值時,進行輸出時鐘時鐘翻轉,同樣經過(n-1)/2時,輸出時鐘再次翻轉生成占空比非50%的奇數n分頻時鐘。兩個占空比非50%的n分頻時鐘進行邏輯運算(正週期多的相與,負週期多的相或),得到占空比為50%的奇數n分頻時鐘。
//輸入訊號,其中clk連線到fpga的c1腳,頻率為12mhz
output clkout;
//輸出訊號,可以連線到led觀察分頻的時鐘
//parameter是verilog裡常數語句
parameter width =3;
//計數器的位數,計數的最大值為 2**width-1
parameter n =5;
//分頻係數,請確保 n < 2**width-1,否則計數會溢位
reg[width-1:
0] cnt_p,cnt_n;
//cnt_p為上公升沿觸發時的計數器,cnt_n為下降沿觸發時的計數器
reg clk_p,clk_n;
//clk_p為上公升沿觸發時分頻時鐘,clk_n為下降沿觸發時分頻時鐘
//上公升沿觸發時計數器的控制
always@(
posedge clk or
negedge rst_n )
//posedge和negedge是verilog表示訊號上公升沿和下降沿
//當clk上公升沿來臨或者rst_n變低的時候執行一次always裡的語句
beginif(
!rst_n)
cnt_p<=0;
else
if(cnt_p==
(n-1))
cnt_p<=0;
else cnt_p<=cnt_p+1;
//計數器一直計數,當計數到n-1的時候清零,這是乙個模n的計數器
end//上公升沿觸發的分頻時鐘輸出,如果n為奇數得到的時鐘占空比不是50%;如果n為偶數得到的時鐘占空比為50%
always@(
posedge clk or
negedge rst_n)
beginif(
!rst_n)
clk_p<=0;
else
if(cnt_p<
(n>>1)
)//n>>1表示右移一位,相當於除以2去掉餘數
clk_p<=0;
else
clk_p<=1;
//得到的分頻時鐘正週期比負週期多乙個clk時鐘
end//下降沿觸發時計數器的控制
always@(
negedge clk or
negedge rst_n)
beginif(
!rst_n)
cnt_n<=0;
else
if(cnt_n==
(n-1))
cnt_n<=0;
else cnt_n<=cnt_n+1;
end//下降沿觸發的分頻時鐘輸出,和clk_p相差半個時鐘
always@(
negedge clk)
beginif(
!rst_n)
clk_n<=0;
else
if(cnt_n<
(n>>1)
) clk_n<=0;
else
clk_n<=1;
//得到的分頻時鐘正週期比負週期多乙個clk時鐘
endassign clkout =
(n==1)
?clk:
(n[0])
?(clk_p&clk_n)
:clk_p;
//條件判斷表示式
//當n=1時,直接輸出clk
//當n為偶數也就是n的最低位為0,n(0)=0,輸出clk_p
//當n為奇數也就是n最低位為1,n(0)=1,輸出clk_p&clk_n。正週期多所以是相與
endmodule
測試檔案,進行功能**時需要編寫testbench測試檔案。verilog裡的testbench檔案和原始檔一樣也是.v檔案,**能讓我們更直觀的觀察訊號波形,可以先閱讀diamond的使用了解如何使用diamond中整合的**工具。
`timescale
1ns/
100ps
//**時間單位/時間精度,時間單位要大於或者等於時間精度
module divide_tb();
//測試檔案也是乙個module,因為用於**所以無需輸入輸出訊號
reg clk,rst_n;
//需要產生的激勵訊號定義,激勵訊號需要過程塊產生所以定義為reg型變數
wire clkout;
//需要觀察的輸出訊號定義,定義為wire型變數
//初始化過程塊
initial
begin
clk =0;
rst_n =0;
#25//#表示延時25個時間單位
rst_n =1;
//產生了乙個初始25ns低電平,然後變高電平的復位訊號
endalways
#10 clk =
~clk;
//每隔10ns翻轉一次clk訊號,也就是產生乙個時鐘週期20ns的clk,頻率為50mhz
//module呼叫例化格式
divide #
(.width(4)
,.n(11)
) u1 (
//#後面的()中為引數傳遞,如果不傳遞引數就是所呼叫模組中的引數預設值
//divide表示所要例化的module名稱,u1是我們定義的例化名稱,必須以字母開頭
.clk (clk)
,//輸入輸出訊號連線。 .clk表示module本身定義的訊號名稱;(clk)表示我們在這裡定義的激勵訊號
.rst_n (rst_n)
,//在testbench裡定義的訊號名稱可以與所要呼叫module的埠訊號名稱不同
.clkout (clkout));
endmodule
時鐘為12mhz。你可以通過**波形觀察分頻時鐘(注意**的時間是有限的,所以分頻時鐘頻率需要較高)。如果我們想通過眼睛觀察led的閃爍,那麼需要設定引數n和width得到乙個頻率較低的時鐘(例如n=12000000,width=24,分頻時鐘週期為1秒)。
訊號引腳
clkc1
rst_n
l14clkout
n13
修改程式中的分頻係數和計數器位數就能夠調整led閃爍速度(注意計數的最大值一定要保證超過分頻係數n)。
關於FPGA的時鐘分頻問題
關於fpga的時鐘分頻問題 在fpga裡面,關於時鐘分頻,可以通過鎖相環來實現,但是,鎖相環的分頻系統受到一定的限制 根據所用的fpga晶元不同,所受到的限制也不一樣 不能隨心所欲的按照自己的想法來分頻。所以,我們可以自己寫乙個分頻的程式,當然,能夠達到分頻的效果,只是精度並沒有像pll的那麼高,但...
Verilog 時鐘偶分頻 奇分頻 任意分頻
分頻器是指使輸出訊號頻率為輸入訊號頻率整數分之一的電子電路。偶分頻計數器 偶分頻比較簡單,假設為n分頻,只需計數到n 2 1,然後時鐘翻轉 計數清零,如此迴圈就可以得到n 偶 分頻。如下 module even divider clk in,rst n,even en,偶分頻使能訊號,方便後續設計任...
FPGA奇數分頻
前注 設計中盡量還是要避免使用自己計數分頻得到的時鐘,去使用廠家自帶的分頻ip 如vivado中的clock wizard 偶數分頻比較簡單,這裡略過。對於不要求占空比為50 的奇數分頻,也比較簡單,直接模n計數,期間進行兩次翻轉就可以了。這裡重點介紹要求占空比為50 的奇數分頻。步驟 1.在時鐘上...