1. 程式人生 > 其它 >FPGA基礎知識之5----分頻器設計(奇數分頻、偶數分頻)

FPGA基礎知識之5----分頻器設計(奇數分頻、偶數分頻)

技術標籤:FPGA學習verilogfpga

前言

將筆者之前在學習FPGA上遇到的一些有意義的內容整理成文,分享給大家,共同探討,共同進步。


前言

1、分頻器?

2、偶數分頻器

2.1、說明

2.2、Verilog

2.3、Testbench

2.4、模擬結果

3、奇數分頻器

3.1、說明

3.2、Verilog

3.3、Testbench

3.4、模擬結果


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倍分頻見下圖: