FPGA基礎知識之5----分頻器設計(奇數分頻、偶數分頻)
阿新 • • 發佈:2021-02-07
前言
將筆者之前在學習FPGA上遇到的一些有意義的內容整理成文,分享給大家,共同探討,共同進步。
1、分頻器?
在數字系統的設計中經常會碰到需要使用多個時鐘的情況。時鐘訊號的產生通常具有兩種方法,一種是使用PLL(Phase Locked Loop,鎖相環),可生成倍頻、分頻訊號;另一種則是使用硬體描述語言構建一個分頻電路。
分頻器的設計通常分為以下三類:奇數分頻器、偶數分頻器及小數分頻器。本文接下來將分別對奇數分頻器及偶數分頻器的設計模擬進行說明。
2、偶數分頻器
2.1、說明
偶數分頻器的原理比較簡單。比如2分頻,則只需要使用基準時鐘在第一個時鐘週期輸出高電平(或低電平),在第二個時鐘週期輸出相反電平,如此反覆即可。
一般方法:假設為 N分頻,只需計數到 N/2-1,然後時鐘翻轉、計數器清零,如 此迴圈就可以得到 N(偶)分頻。
2.2、Verilog
//偶數分頻器 module even( input sys_clk, //基準時鐘 input sys_rst_n,//復位 output reg clk_even);//輸出分頻時鐘 parameter divide=2;//分頻係數,可設定 reg [9:0] cnt;//計數器 always @(posedge sys_clk or negedge sys_rst_n)begin if(!sys_rst_n)begin//復位將狀態初始化 cnt<=10'd0; clk_even<=1'b0; end else begin if(cnt<divide/2-1)begin//每計數divide/2個時鐘,則將輸出反轉,然後計時器清零 cnt<=cnt+1'b1; clk_even<=clk_even; end else begin cnt<=10'd0; clk_even<=~clk_even; end end end endmodule
2.3、Testbench
`timescale 1ns/1ns //時間刻度1納秒 module even_tb(); //輸入定義 reg sys_clk; reg sys_rst_n; reg clk_even; //例化被測試模組 even i1( .sys_clk(sys_clk), .sys_rst_n(sys_rst_n), .clk_even() ); initial begin sys_clk=1'b0;//初始化設定 sys_rst_n=1'b0;//初始化設定 clk_even=1'b0;//初始化設定 #10 sys_rst_n=1'b1;//10納秒後,停止復位 end always begin #10 sys_clk=~sys_clk;//設定基準時鐘週期為20納秒 end endmodule
2.4、模擬結果
2分頻模擬結果如下:
6分頻模擬結果如下:
3、奇數分頻器
3.1、說明
實現奇數分頻原理是分別用上升沿計數0到 divide/2,分頻後輸出時鐘進行翻轉,再從0計數到 N/2-1 輸出 第1個時鐘訊號clk_odd1, 再用下降沿重複以上操作輸出第2個時鐘訊號 clk_odd2,然後將兩個時鐘訊號相或即可。
3.2、Verilog
//奇數分頻器
module odd(
input sys_clk, //基準時鐘
input sys_rst_n,//復位
output clk_odd);//輸出分頻時鐘
parameter divide=5;//分頻係數,可設定
reg [9:0] cnt1,cnt2;//計數器1,2
reg clk_odd1,clk_odd2; //分別輸出兩個時鐘
assign clk_odd=clk_odd1||clk_odd2;//將兩個時鐘相或
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin//復位將狀態初始化
cnt1<=10'd0;
clk_odd1<=1'b0;
end
else begin
if(clk_odd1==1'b0)begin
if(cnt1==divide/2)begin
cnt1<=1'b0;
clk_odd1<=~clk_odd1;
end
else
cnt1<=cnt1+1'b1;
end
else if(cnt1==divide/2-1'b1)begin
cnt1<=1'b0;
clk_odd1<=~clk_odd1;
end
else
cnt1<=cnt1+1'b1;
end
end
always @(negedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin//復位將狀態初始化
cnt2<=10'd0;
clk_odd2<=1'b0;
end
else begin
if(clk_odd2==1'b0)begin
if(cnt2==divide/2)begin
cnt2<=1'b0;
clk_odd2<=~clk_odd2;
end
else
cnt2<=cnt2+1'b1;
end
else if(cnt2==divide/2-1'b1)begin
cnt2<=1'b0;
clk_odd2<=~clk_odd2;
end
else
cnt2<=cnt2+1'b1;
end
end
endmodule
3.3、Testbench
`timescale 1ns/1ns //時間刻度1納秒
module odd_tb();
//輸入定義
reg sys_clk;
reg sys_rst_n;
wire clk_odd;
//例化被測試模組
odd i1(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.clk_odd(clk_odd)
);
initial begin
sys_clk=1'b0;//初始化設定
sys_rst_n=1'b0;//初始化設定
#25 sys_rst_n=1'b1;//25納秒後,停止復位
end
always begin
#10 sys_clk=~sys_clk;//設定基準時鐘週期為20納秒
end
endmodule
3.4、模擬結果
5倍分頻見下圖:
7倍分頻見下圖: