FPGA分频器设计(偶数分频、奇数分频)

在数字系统设计中,时钟信号产生有使用PLL和硬件描述语言构建分频电路两种方法。博客详细介绍了偶数分频器和奇数分频器的设计方法,给出8分频和7分频电路设计实例,包含Verilog代码、Testbench编写及仿真结果,还提供了版本信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、什么是分频器


在数字系统的设计中经常会碰到需要使用多个时钟的情况。时钟信号的产生通常具有两种方法,一种是使用PLL(Phase Locked Loop,锁相环),可生成倍频、分频信号;另一种则是使用硬件描述语言构建一个分频电路。

分频器的设计通常分为以下三类:奇数分频器、偶数分频器及小数分频器。接下来分别对偶数分频器及奇数分频器的设计仿真进行说明。

2、偶数分频器

2.1、设计方法

如图所示,分别画出了基准时钟、2分频时钟、4分频时钟、8分频时钟。

通过对波形的观察,不难得到:

2分频设计,只需要使用基准时钟在第1个时钟周期输出高电平(或低电平),在第2个时钟周期输出相反电平,如此反复即可。

同理,4分频设计:使用基准时钟在第1、2个时钟周期输出高电平(或低电平),在第3、4个时钟周期输出相反电平,如此反复即可。

同理,8分频设计:使用基准时钟在第1、2、3、4个时钟周期输出高电平(或低电平),在第5、6、7、8个时钟周期输出相反电平,如此反复即可。

由此可以推导出偶数分频设计的一般方法:假设为N分频,只需设计一个计数器从0计数到 N/2-1(一共N/2个基准时钟),然后将输出分频时钟翻转、计数器清零,如此循环就可以得到 N分频。

2.2、8分频电路设计实例

接下来将设计一个8分频电路并对其进行仿真验证。

8分频电路模块框图如下:

输入:

        sys_clk:基准时钟信号(这里设定为50MHz,周期20ns)

        sys_rst_n:低电平有效的复位信号

输出:

        clk_8:基准时钟信号的8分频信号(50/8=6.25MHz,周期160ns)    

根据前文提到的方法,设计过程如下:

  • 设计一个计数器进行计数(一直从0计数到3(8/2-1),清零再重复)
  • 每次计数器计数到最大值,将8分频信号进行反转

理论上8分频模块的各个信号波形应该如下图所示:

2.2、Verilog

根据上图可以编写Verilog代码如下:

//8分频电路设计
module divider_8                //模块名
(
	input		sys_clk,	    //时钟(设定为 50MHz)
	input		sys_rst_n,	    //复位信号(n 表示低电平有效)
	
	output	reg	clk_8		    //输出8分频信号
);

reg [1:0]	cnt;                //reg 定义  

//计数模块
//从0计数到3共计4个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cnt <= 2'd0;			//复位清零
	else if(cnt == 2'd3)		//从0开始计数,所以需要 -1
		cnt <= 2'd0;			//计满则清零
	else
		cnt <= cnt + 2'd1; 		//没记满就一直计数
end

//8分频时钟输出模块
//满足计数条件则对8分频时钟进行反转
//8分频时钟每隔4个周期反转一次,所以8分频的周期即为8个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)                  
		clk_8 <= 1'b0;          //复位清零
	else if(cnt == 2'd3)  		//记满4个时钟周期
		clk_8 <= ~clk_8;        //计满则输出反转
	else                            
		clk_8 <= clk_8; 		//没记满就保持原来状态
end

endmodule

2.3、Testbench

Testbench文件的编写比较简单,不需要定义或者干其他什么事情,只需要实例化一下我们刚刚设计好的8分频模块就好了。

`timescale 1ns/1ns		//时间刻度:单位1ns,精度1ns

module tb_divider_8();	//仿真模块

//输入reg 定义
reg	sys_clk;			
reg sys_rst_n;

//输出wire定义
wire clk_8;

//设置初始化条件
initial begin
	sys_clk = 1'b0;		//初始时钟为0
	sys_rst_n <= 1'b0;	//初始复位为0
	#10					//10个时间单位后
	sys_rst_n <= 1'b1;  //拉高复位(此时复位无效)
end

//always代表重复进行,#10代表每10个时间单位
//每10个时间单位反转时钟,即时钟周期为20个时间单位(20ns)
always #10 sys_clk = ~sys_clk;	

//例化被测试模块
divider_8 divider_8_inst
(
	.sys_clk 	(sys_clk ), 		
	.sys_rst_n 	(sys_rst_n ), 				

	.clk_8 		(clk_8 ) 		
);
	
endmodule

2.4、仿真结果

使用ModelSim执行仿真,仿真出来的波形如所示:

从波形图可以看到

  • 10ns后停止复位
  • 计数器cnt一直在从0计数到3
  • 每当cnt计数到3,8分频时钟输出就会翻转一次
  • 输出的8分频信号周期刚好为8个基准时钟周期

3、奇数分频器

3.1、设计方法

如图所示,分别画出了基准时钟、3分频时钟、5分频时钟、7分频时钟。

不难想到3分频信号的周期为基准时钟信号周期的3倍,那么3分频时钟信号的边沿变化肯定发生在第1.5个时钟周期(第2个时钟周期的下降沿),同理5分频的边沿变化肯定发生在第2.5个时钟周期(第3个时钟周期的下降沿),同理7分频的边沿变化肯定发生在第3.5个时钟周期(第4个时钟周期的下降沿)。同时我们会发现既然边沿的变化都发生在0.5个时钟周期,那么肯定要利用到时钟的下降沿。

3.2、7分频电路设计实例

根据上图的7分频为例,可以得到以下结论:

  • L3到L7为7分频的1个完整的时钟周期,同时也是7个基准时钟周期,即7分频
  • L3(红线3,其他红线命名类推)到L4为7分频的半个时钟周期(高电平),同时也是3.5个基准时钟周期
  • L4到L7为7分频的半个时钟周期(低电平),同时也是3.5个基准时钟周期
  • clk_pos为上升沿敏感信号,分为两段,前半段占3个基准时钟周期(0~2),后半段占4个基准时钟周期(3~6)
  • clk_neg为下降沿敏感信号,分为两段,前半段占3个基准时钟周期(0~2),后半段占4个基准时钟周期(3~6)
  • 将 clk_pos 和 clk_neg 相与(&&)就可以得到7分频电路

从7分频电路可以推导出奇数分频设计的一般方法:

  • 假设为 N分频,需从0计数到 N-1(一共N/2个基准时钟),一直循环
  • 设计一个对基准时钟上升沿敏感的信号,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再反转
  • 设计一个对基准时钟下降沿敏感的信号,每当计数到(N-1)/2-1时,时钟翻转;计数到计数器最大值时再反转
  • 将 上升沿敏感的信号和 下降沿敏感的信号相与(&&)即N分频电路

7分频电路模块框图如下:

输入:

        sys_clk:基准时钟信号(这里设定为50MHz,周期20ns)

        sys_rst_n:低电平有效的复位信号

输出:

        clk_7:基准时钟信号的7分频信号(50/7=7.14MHz,周期140ns)

3.3、Verilog

根据上文分析不难编写Verilog代码如下:

module divider_7                    //模块名
(
	input		sys_clk,			//时钟(设定为 50MHz)
	input		sys_rst_n,			//复位信号(n 表示低电平有效)
			
	output		clk_7				//输出7分频信号
);		
//reg 定义		
reg [2:0]	cnt;					//最大为6,所以需要3位位宽
reg			cnt_pos;				//上升沿敏感信号
reg			cnt_neg;				//下降沿敏感信号

assign clk_7 = cnt_pos && cnt_neg;	//组合逻辑 与 

//计数模块,从0计数到6共计7个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)
		cnt <= 3'd0;				//复位清零
	else if(cnt == 3'd6)			//从0开始计数,所以需要 -1
		cnt <= 3'd0;				//计满则清零
	else	
		cnt <= cnt + 3'd1; 			//没记满就一直计数
end

//cnt_pos:上升沿触发
//低电平维持3个基准时钟周期,高电平维持4个时钟周期
always@(posedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)                  
		cnt_pos <= 1'b0;          	//复位清零
	else if(cnt == 3'd2)  			//记满3个时钟周期
		cnt_pos <= 1'b1;         	//前3个时钟周期输出为0,满足条件则输出1
	else if(cnt == 3'd6)  			//记满7个时钟周期
		cnt_pos <= 1'b0;         	//后4个时钟周期输出为1,满足条件则输出0	
	else                            
		cnt_pos <= cnt_pos; 		//不满足条件就保持原来状态
end


//cnt_neg:下降沿触发
//低电平维持3个基准时钟周期,高电平维持4个时钟周期
always@(negedge sys_clk or negedge sys_rst_n)begin
	if(!sys_rst_n)                  
		cnt_neg <= 1'b0;          	//复位清零
	else if(cnt == 2'd2)  			//记满3个时钟周期
		cnt_neg <= 1'b1;        	//前3个时钟周期输出为0,满足条件则输出1
	else if(cnt == 3'd6)  			//记满7个时钟周期
		cnt_neg <= 1'b0;         	//后4个时钟周期输出为1,满足条件则输出0		
	else                            
		cnt_neg <= cnt_neg; 		//不满足条件就保持原来状态
end

endmodule

3.4、Testbench

Testbench文件比较简单,只需要实例化一下我们刚刚设计好的7分频模块就好了。

`timescale 1ns/1ns		//时间刻度:单位1ns,精度1ns

module tb_divider_7();	//仿真模块

//输入reg 定义
reg	sys_clk;			
reg sys_rst_n;

//输出wire定义
wire clk_7;

//设置初始化条件
initial begin
	sys_clk = 1'b0;		//初始时钟为0
	sys_rst_n <= 1'b0;	//初始复位
	#10					//10个时间单位后
	sys_rst_n <= 1'b1;  //拉高复位(此时复位无效)
end

//always代表重复进行,#10代表每10个时间单位
//每10个时间单位反转时钟,即时钟周期为20个时间单位(20ns)
always #10 sys_clk = ~sys_clk;	

//例化被测试模块
divider_7 divider_7_inst
(
	.sys_clk 	(sys_clk ), 		
	.sys_rst_n 	(sys_rst_n ), 				

	.clk_7 		(clk_7 ) 		
);
	
endmodule

3.5、仿真结果

使用ModelSim执行仿真,仿真出来的波形如所示:

从波形图可以看到

  • 10ns后停止复位
  • 计数器cnt一直在从0计数到6
  • 每当cnt计数到3的上升沿(L2),cnt_pos信号输出翻转,每当cnt计数清零(L4),cnt_pos信号输出翻转
  • 每当cnt计数到3的下降沿(L1),cnt_neg信号输出翻转,每当cnt计数清零(L3),cnt_neg信号输出翻转
  • 从L2到L3为7分频信号的半个时钟周期(高电平),从L2到L3为8分频信号的半个时钟周期(低电平)
  • 从L2到L6为7分频信号的1个完整的时钟周期,同时也是7个基准时钟周期

4.其他

版本信息

        文件:V1.0

        编号:5

        Vivado:无

        Modelsim:Modelsim SE-64 10.4

        Quartus II:无

评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤独的单刀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值