小数分频之N.5分频原理及其实现(占空比非常接近0.5)


写在前面(重要)(本次设计只适用于对占空比要求不是很严格的设计,设计出来的时钟 高低电平之比为N:N+1或者N+1:N 本人觉得这已经算是0.5分频的极限了

设计小数分频时,假如 不使用外部资源,只是用FPGA内部逻辑资源(即只有一个输入时钟clk_in以及一些计数器和线网,不使用锁相环),最后设计出来的输出时钟clk_out 不可能达到真正的占空比为50%。

如果用锁相环倍频的话,那假如设计一个输入时钟clk_in的3.5分频。使用2倍频的话,其实就相当于设计的是clk_in 2倍频之后的7分频(即一个奇数分频);而使用4倍频的话,其实就相当于设计的是clk_in 4倍频之后的14分频(即一个偶数分频)。

这样虽然设计出来了,但是却比较浪费资源,并且也根本算不上是小数分频。

一、常规设计思路

常规设计思路如下:

假设设计一个3.5分频,我们令半个clk_in周期为一个clk,后面我们以clk为单位,而不用clk_in的一个完整周期。

3.5分频即有7个clk为它的一个完整周期,N.5分频就有2N+1个clk,那么肯定高电平时间和低电平时间是不可能一样的,具体原理如下图,这也是仿真结果图(其实就是自己不想画图):
0.5分频原理
说明一下:第一行是时钟信号clk_in; 第二行是复位信号rst_n; 第三行是clk_p,上升沿翻转时钟
第四行是clk_n,下降沿翻转时钟第五行是clk_N_point5,就是输出时钟

假设从最左侧蓝线处算作初始化,(注意:初始化的时候,也就是下降沿复位的话,对clk_p和clk_n的赋值一定要相反,可以让clk_p为0,clk_n为1)

具体如何计数呢?

复位之后,在一个上升沿进行上升沿计数,计数到6清零,并且在0和4的时候进行翻转(计数到2N清零,并且在0和N+1的时候进行翻转),得到clk_p;
复位之后,在一个下降沿进行下降沿计数,计数到6清零,并且在0和3的时候进行翻转(计数到2N清零,并且在0和N的时候进行翻转),得到clk_n;

最后,对clk_p和clk_n进行与运算,得到clk_N_point5 ; clk_N_point5 = clk_p && clk_n;
在这里插入图片描述
仿真效果如下:
在这里插入图片描述
但是可以看到:输出时钟的占空比非常低,占空比为 1:2N+1,如果N更大一些,占空比会更小。

二、改进设计思路

不想画图,放出改进后的原理图:
在这里插入图片描述
复位之后,在一个上升沿进行上升沿计数,计数到6清零,并且在0和5的时候进行翻转,得到clk_p;
复位之后,在一个下降沿进行下降沿计数,计数到6清零,并且在1和3的时候进行翻转,得到clk_n;

最后,对clk_p和clk_n进行与运算,得到clk_N_point5 ; clk_N_point5 = clk_p && clk_n;

这是当N==3的时候,在这些地方翻转,那当N为其他值呢?经过我的带入—纸上—递归法得到:

对任意N:复位之后,在一个上升沿进行上升沿计数,计数到2N清零,并且在0和N+1+N/2的时候进行翻转,得到clk_p;
复位之后,在一个下降沿进行下降沿计数,计数到6清零,并且在N/2和N的时候进行翻转,得到clk_n。

三、仿真效果

N=3:
在这里插入图片描述
N=5:
在这里插入图片描述
N=20:
在这里插入图片描述
可以看出:高低电平总是只相差半个clk_in,当N越大,输出时钟的占空比也越大,越接近50%

四、源代码以及仿真文件

1、源代码

`timescale 1ns / 1ps

module divider_point5 #(parameter CLK_N = 2)
(
	input				clk_in,
	input				rst_n,
	
	output	reg			clk_2in,				// 2N倍频时钟
	output	reg			clk_2in_2,				// 下降沿2N倍频时钟
	//output				clk_en,
	output				clk_N_point5,
	output	reg			clk_out
    );
    
    reg		[7:0]		cnt_2N;					// 2N倍频时钟计数
    reg		[7:0]		cnt_2N_2;				// 下降沿2N倍频时钟计数
    
    reg					clk_out_g1;
    
    
    
    assign			clk_N_point5 = 	clk_2in && clk_2in_2;
    
    // 上升沿生成2N分频时钟电路
    always@(posedge clk_in or negedge rst_n) begin
    	if(!rst_n)
    		cnt_2N <= 8'b0;
    	else if(cnt_2N == 2*CLK_N)
    		cnt_2N <= 8'b0;
    	else 
    		cnt_2N <= cnt_2N + 1'b1;
    end
    always@(posedge clk_in or negedge rst_n) begin
    	if(!rst_n)
    		clk_2in <= 1'b0;
    	//else if((cnt_2N == CLK_N+1) ||( cnt_2N ==0 )) begin			// 这个是占空比为1:2N+1,未改进
    	else if((cnt_2N == CLK_N+1+CLK_N/2) ||( cnt_2N ==0 )) begin		// 这个是占空比尽量靠近0.5的方式
    		clk_2in <= ~clk_2in;
    	end
    	else 
    		clk_2in <= clk_2in;
    end
    
    // 下降沿生成2N分频时钟电路
    always@(negedge clk_in or negedge rst_n) begin
    	if(!rst_n)
    		cnt_2N_2 <= 8'b0;
    	else if(cnt_2N_2 == 2*CLK_N)
    		cnt_2N_2 <= 8'b0;
    	else 
    		cnt_2N_2 <= cnt_2N_2 + 1'b1;
    end
    always@(negedge clk_in or negedge rst_n) begin
    	if(!rst_n)
    		clk_2in_2 <= 1'b1;
    	//else if((cnt_2N_2 == CLK_N) ||( cnt_2N_2 == 0 )) begin		// 这个是占空比为1:2N+1,未改进
    	else if((cnt_2N_2 == CLK_N) ||( cnt_2N_2 == CLK_N/2 )) begin	// 这个是占空比尽量靠近0.5的方式
    		clk_2in_2 <= ~clk_2in_2;
    	end
    	else 
    		clk_2in_2 <= clk_2in_2;
    end  
    
    
endmodule

2、仿真文件

`timescale 1ns / 1ps
`define clk_period 20


module divider_point5_tb();

parameter CLK_N = 20;

reg					clk_in;
reg					rst_n;

wire				clk_2in;
wire				clk_2in_2;
wire				clk_N_point5;

initial begin
	rst_n = 1;
	clk_in = 0;
	#2;
	rst_n = 0;
	#3;
	rst_n = 1;
end

always #(`clk_period/2) clk_in = ~clk_in;

divider_point5 #(.CLK_N	(CLK_N))
	divider_point5(
		.clk_in			(clk_in),
		.rst_n			(rst_n),
		.clk_2in		(clk_2in),
		.clk_2in_2		(clk_2in_2),
		.clk_N_point5	(clk_N_point5)
	);


endmodule

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值