Verilog 任意分频器设计

实际工程中要产生分频时钟一般采用FPGA的时钟管理器来进行分频、倍频,通过设置一下IP核中的参数即可,这样做有很多别的方法(例如:直接用Verilog HDL设计分频电路)达不到的效果,产生时钟的质量也更好,因此,一般而言,也推荐这种方法,但这并非意味着直接用Verilog HDL设计分频电路一无是处,毫无用途。

如果对时钟的性能要求不高,我就自然就可以用这种方法产生分频时钟,这样就只消耗了少量的资源而实现了时钟的分频要求,我们把这种设计叫做分频器设计。
 

偶分频

偶分频电路,一般做法是通过计数器计数。如要实现10分频(计数器从0开始计数),则计数上限为(10 - 1)= 9,达到计数值(10/2 - 1)= 4,后输出时钟取反同时计数器继续累加1,知道计数器达到(10 - 1)= 9,输出时钟再次取反。(也可在计数器到4时清零,计数上限为4)

例如N分频(N为偶数),用计数器计数基准时钟周期个数cnt(cnt初值为0),计数上限为(N/2- 1 ),当cnt为(N/2- 1 )时候,分频时钟翻转一次,同时cnt清零,继续计数。
 

	//偶分频
	always @ (posedge clk or negedge rst_n) begin 
		if(!rst_n) begin
			clk_even_cnt <= 0;
			clk_even <= 1'b0;
			end
		else if(clk_even_cnt == CLK_DIV/2 - 1) begin 
			clk_even_cnt <= clk_even_cnt + 1'b1;
			clk_even <= ~ clk_even;
			end
		else if(clk_even_cnt == CLK_DIV - 1) begin 
			clk_even_cnt <= 0;
			clk_even <= ~ clk_even;
			end
		else begin 
			clk_even_cnt <= clk_even_cnt + 1'b1;
			clk_even <= clk_even;
			end
		end
		

奇分频

占空比为50%的奇分频

首先看占空比为50%的奇分频,也就分频后的时钟的占空比为50%,高低电平持续时间一致。

由于奇分频需要保持分频后的时钟占空比为50%,所以不能想偶分频直接在分频系数的一般时使时钟信号翻转,接下来设计一个5分频的模块,设计思路如下:

采用计数器cnt1对时钟上升沿计数,计数从0开始。计数值为0、1时,输出时钟信号clk1_div为高电平,计数值为2、3、4时,输出时钟信号clk1_div 为低电平,计数器计到4时清零。得到占空比为2/5的波形clk1_div 。

采用计数器cnt2对时钟下降沿计数,计数从0开始。计数值为0、1时,输出时钟信号clk2_div为高电平,计数值为2、3、4时,输出时钟信号clk2_div 为低电平,计数器计到4时清零。得到占空比为2/5的波形clk2_div 。

clk1_div和clk2_div的上升沿时间间隔为半个时钟周期,将两个时钟信号进行或运算,即可得到占空比为50%的分频时钟。

//奇分频——clk1:上升沿触发
always @(posedge clk or negedge rst_n) begin
	if(!rst_n)
		begin
			clk1_odd_cnt	<= 0	;
			r_clk_1		<= 1'b0	;
		end
	else if(clk1_odd_cnt == (CLK_DIV - 1) / 2)		//计数到一半时翻转,计数器继续加
		begin
			clk1_odd_cnt	<= clk1_odd_cnt + 1'b1	;	
			r_clk_1		<= ~r_clk_1			;
		end	
	else if(clk1_odd_cnt == CLK_DIV - 1)			//计数满时翻转,计数器清零
		begin
			clk1_odd_cnt	<= 0		;
			r_clk_1		<= ~r_clk_1	;
		end		
	else
		begin
			clk1_odd_cnt	<= clk1_odd_cnt + 1'b1	;	
			r_clk_1		<= r_clk_1			;
		end
end
	
	//奇分频——clk2:下降沿触发
	always @(negedge clk or negedge rst_n) begin
		if(!rst_n)
			begin
				clk2_odd_cnt	<= 0	;
				r_clk_2		<= 1'b0	;
			end
		else if(clk2_odd_cnt == (CLK_DIV - 1) / 2)		//计数到一半时翻转,计数器继续加
			begin
				clk2_odd_cnt	<= clk2_odd_cnt + 1'b1	;	
				r_clk_2		<= ~r_clk_2			;
			end	
		else if(clk2_odd_cnt == CLK_DIV - 1)			//计数满时翻转,计数器清零
			begin
				clk2_odd_cnt	<= 0		;
				r_clk_2		<= ~r_clk_2	;
			end		
		else
			begin
				clk2_odd_cnt	<= clk2_odd_cnt + 1'b1	;	
				r_clk_2		<= r_clk_2			;
			end
	end

实现任意奇、偶分频的分频器

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 

//

 module divier
#(
	parameter	CLK_DIV= 8'd5,		//分频数
				CNT_WIDTH 	= 4'd5		//分频位宽
)
(
    input           clk,      
	input           rst_n,
	output			out_clk,
	output			clk_1,
	output			clk_2,
	output reg	[CNT_WIDTH - 1 : 0]		clk_even_cnt	,
	output reg	[CNT_WIDTH - 1 : 0]		clk1_odd_cnt	,
	output reg	[CNT_WIDTH - 1 : 0]		clk2_odd_cnt	
);

	//偶分频
	reg 									clk_even			;
//	reg	[CNT_WIDTH - 1 : 0]		clk_even_cnt	;
	
	//奇分频
	wire									clk_odd			;
	reg									r_clk_1				;
	reg									r_clk_2 			;
//	reg	[CNT_WIDTH - 1 : 0]		clk1_odd_cnt	;		
//	reg	[CNT_WIDTH - 1 : 0]		clk2_odd_cnt	;
	
	assign out_clk = (!CLK_DIV) ? clk : (CLK_DIV[0] ? clk_odd : clk_even);
	assign clk_odd = clk_1 | clk_2;
	
	//偶分频
	always @ (posedge clk or negedge rst_n) begin 
		if(!rst_n) begin
			clk_even_cnt <= 0;
			clk_even <= 1'b0;
			end
		else if(clk_even_cnt == CLK_DIV/2 - 1) begin 
			clk_even_cnt <= clk_even_cnt + 1'b1;
			clk_even <= ~ clk_even;
			end
		else if(clk_even_cnt == CLK_DIV - 1) begin 
			clk_even_cnt <= 0;
			clk_even <= ~ clk_even;
			end
		else begin 
			clk_even_cnt <= clk_even_cnt + 1'b1;
			clk_even <= clk_even;
			end
		end
		
	//奇分频--clk1:上升沿触发
always @(posedge clk or negedge rst_n) begin
	if(!rst_n)
		begin
			clk1_odd_cnt	<= 0	;
			r_clk_1		<= 1'b0	;
		end
	else if(clk1_odd_cnt == (CLK_DIV - 1) / 2)		//计数到一半时翻转,计数器继续加
		begin
			clk1_odd_cnt	<= clk1_odd_cnt + 1'b1	;	
			r_clk_1		<= ~r_clk_1			;
		end	
	else if(clk1_odd_cnt == CLK_DIV - 1)			//计数满时翻转,计数器清零
		begin
			clk1_odd_cnt	<= 0		;
			r_clk_1		<= ~r_clk_1	;
		end		
	else
		begin
			clk1_odd_cnt	<= clk1_odd_cnt + 1'b1	;	
			r_clk_1		<= r_clk_1			;
		end
end
	
	//奇分频--clk2:下降沿触发
	always @(negedge clk or negedge rst_n) begin
		if(!rst_n)
			begin
				clk2_odd_cnt	<= 0	;
				r_clk_2		<= 1'b0	;
			end
		else if(clk2_odd_cnt == (CLK_DIV - 1) / 2)		//计数到一半时翻转,计数器继续加
			begin
				clk2_odd_cnt	<= clk2_odd_cnt + 1'b1	;	
				r_clk_2		<= ~r_clk_2			;
			end	
		else if(clk2_odd_cnt == CLK_DIV - 1)			//计数满时翻转,计数器清零
			begin
				clk2_odd_cnt	<= 0		;
				r_clk_2		<= ~r_clk_2	;
			end		
		else
			begin
				clk2_odd_cnt	<= clk2_odd_cnt + 1'b1	;	
				r_clk_2		<= r_clk_2			;
			end
	end

	assign clk_1 = r_clk_1;
	assign clk_2 = r_clk_2;
endmodule		
		

 testbench

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
//

module divier_testbench(

    );


reg clk;
reg rst_n;
// wires                                               
wire out_clk;
wire clk_1;
wire clk_2;//wire [2:0] cnt;
 wire	[5 - 1 : 0]		clk_even_cnt	;
 wire	[5 - 1 : 0]		clk1_odd_cnt	;
 wire	[5 - 1 : 0]		clk2_odd_cnt	;
                          
divier i1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.out_clk(out_clk),
	.rst_n(rst_n),
	.clk_1(clk_1),
	.clk_2(clk_2),

	.clk_even_cnt(clk_even_cnt),
	.clk1_odd_cnt(clk1_odd_cnt),
	.clk2_odd_cnt(clk2_odd_cnt)
);
initial                                                
begin                                                                           
 clk = 1;
 rst_n  = 0;
 #10 rst_n = 1;                     
end                                                    
always                                                                   
begin                                                                           
 #10 clk = ~clk;                                                                                                  
end                                                    
endmodule

 

  • 1
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无牙大白鲨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值