FPGA时钟分频:偶数分频、奇数分频、小数分频(含verilog源码)-程序员宅基地

技术标签: fpga开发  

前言

  FPGA分频器是一种常用于数字信号处理、通信系统、雷达系统等领域的电路,其作用是将信号时钟分成多个频频率。分频电路是数字电路中常见的逻辑电路类型。在时序逻辑电路中,时钟是必不可少的,但对于时钟要求不高的基本设计,自行设计的分频电路,也就是时钟分频器,有时候比采用外部PLL更为简单、有效、快速。本文将详细介绍FPGA分频器的设计方法,并附上Verilog代码示例,以供参考。

  分频器一般可以分为:偶数分频、奇数分频、小数分频。

1、偶数分频

(1)用D触发器级联实现

  将主时钟以2为幂次进行分割可以得到同步偶数分频时钟,即21,22,23…分频。电路上可采用D触发器实现,n个触发器可以构成2n次偶数分频。如图1所示,为2分频、4分频电路设计及波形。

(a)2分频电路及波形

(b)4分频电路及波形
图1 偶数分频电路设计

(2)用计数器实现

  用D触发器级联搭建分频电路只能实现2,4,8,16等分频,对于一般的偶数分频,可以通过计数器实现:若要实现N分频(N为偶数),只需将计数器在待分频时钟上升沿触发下循环计数,从0计数到(N/2 -1)后将输出时钟翻转即可实现。代码见工程Even_clk_freq_div。仿真图和代码如下:

	//N为偶数分频的值,实现50%占空比的偶数分频
	parameter N = 6;
	
	reg [2:0] cnt;
	
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)begin
			cnt <= 3'd0;
			clk_out <= 1'b0;
		end
		else if (cnt == (N-1)/2)begin
			cnt <= 3'd0;
			clk_out <= ~clk_out;
		end
		else
			cnt <= cnt + 1'b1;

2、奇数分频

(1)占空比非50%的奇数分频

① 用Moore状态机实现

  以7分频为例,通过如图2所示Moore状态机即可实现输入时钟的7分频。

图2 7分频电路Moore状态机

  值得注意的是,上图实现的7分频的占空比并非50%。代码见工程Odd_clk_freq_div_Moore。仿真和代码截图如下:

parameter 	state_0 = 3'd0,
				state_1 = 3'd1,
				state_2 = 3'd2,
				state_3 = 3'd3,
				state_4 = 3'd4,
				state_5 = 3'd5,
				state_6 = 3'd6;
				
	reg [2:0] State,next_state;	
	
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			State <= state_0;
		else
			State <= next_state;
			
	always @(*)
		if (!rst_n)
			next_state <= state_0;
		else begin
			case (State)
				state_0	:	next_state = state_1;
				state_1	:	next_state = state_2;
				state_2	:	next_state = state_3;
				state_3	:	next_state = state_4;
				state_4	:	next_state = state_5;
				state_5	:	next_state = state_6;
				state_6	:	next_state = state_0;
				default	:	next_state = state_0;
			endcase
		end
		
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_out <= 1'b0;
		else begin
			case(next_state)
				state_0	:	clk_out <= 1'b0;
				state_1	:	clk_out <= 1'b0;
				state_2	:	clk_out <= 1'b0;
				state_3	:	clk_out <= 1'b0;
				state_4	:	clk_out <= 1'b1;
				state_5	:	clk_out <= 1'b1;
				state_6	:	clk_out <= 1'b1;
				default	:	clk_out <= 1'b0;
			endcase
		end

② 用计数器实现

  其实用状态机实现占空比非50%的分频电路还是比较麻烦的,可以采用计数器的方法:若要实现N分频(N为奇数),只需将计数器在待分频时钟上升沿触发下循环计数,从0计数到(N-1)后计数器清零。当计数到(N-1)/2后将输出时钟翻转,计数到0后再次翻转即可实现。代码见工程Odd_clk_freq_div0。仿真和代码如下:

 //N为奇数分频的值,实现非50%占空比的奇数分频
	parameter N = 7;
	
	reg [2:0] cnt;
	
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			cnt <= 3'd0;
		else if (cnt == (N-1))
			cnt <= 3'd0;
		else
			cnt <= cnt + 1'b1;
			
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_out <=1'b0;
		else if (cnt == (N-1)/2)
			clk_out <= ~clk_out;
		else if (cnt == 3'b0)
			clk_out <= ~clk_out;
		else
			clk_out <= clk_out;

(2)占空比50%的奇数分频

  对于奇数分频,就是分别利用待分频时钟的上升沿触发生成一个时钟,然后用下降沿触发生成另一个时钟,然后将两个时钟信号进行或/与运算得到占空比为50%的奇数分频。上面一小节已经介绍了如何利用待分频时钟的上升沿触发生成占空比非50%的时钟,只需再类似地利用待分频时钟的下降沿触发生成占空比非50%的时钟。具体方法详述如下:

  ① 设计2个分别用上升、下降沿触发的计数器
定义2个计数器cnt_p和cnt_n,分别利用时钟的上升沿和下降进行触发计数

  ② 利用上升、下降沿计数器生成两个分频时钟clk_p和clk_n
定义2个时钟信号clk_p和clk_n, 对于上升沿计数器cnt_p,当计数到0或者(N-1)/2时,均翻转clk_p信号;对于下降沿计数器cnt_n,当计数到0或者(N-1)/2时,均翻转clk_n信号。

  ③ 利用clk_p和clk_n通过逻辑运算生成占空比为50%的分频时钟
若clk_p和clk_n初始复位为0,将2个时钟clk_p和clk_n通过或运算即可生成占空比为50%的分频时钟,且clk_out上升沿和原时钟上升沿对齐。代码见工程Odd_clk_freq_div1。仿真截图和代码如下:

//N为奇数分频的值,实现50%占空比的奇数分频
	parameter N = 7;
	reg [2:0] cnt_p, cnt_n;
	reg	clk_p;
	reg	clk_n;
	
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			cnt_p <= 3'd0;
		else if (cnt_p == (N-1))
			cnt_p <= 3'd0;
		else
			cnt_p <= cnt_p + 1'b1;
			
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_p <=1'b0;
		else if (cnt_p == (N-1)/2)
			clk_p <= ~clk_p;
		else if (cnt_p == 3'b0)
			clk_p <= ~clk_p;
		else
			clk_p <= clk_p;
			
	//将clk_p打半拍得到clk_n
	always @(negedge clk_in or negedge rst_n)
		if (!rst_n)
			cnt_n <= 3'd0;
		else if (cnt_n == (N-1))
			cnt_n <= 3'd0;
		else
			cnt_n <= cnt_n + 1'b1;
			
	always @(negedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_n <=1'b0;
		else if (cnt_n == (N-1)/2)
			clk_n <= ~clk_n;
		else if (cnt_n == 3'b0)
			clk_n <= ~clk_n;
		else
			clk_n <= clk_n;	
			
	assign clk_out = clk_p | clk_n;		              

详细的波形图如图3所示:

图3 占空比为50%的7分频电路波形生成

  还有一种更简便的方法只需要一个计数器cnt_p就可以,通过cnt_p产生clk_p时钟,然后直接用待分频时钟下降沿对时钟clk_p打半拍得到时钟clk_n,最后将clk_p和clk_n相或就可以得到占空比为50%的7分频时钟。代码见工程Odd_clk_freq_div,个人比较推荐这种写法,里面涉及到对信号打半拍,理解到了对学习FPGA大有帮助。下面是仿真结果图和代码截图。

//N为奇数分频的值,实现50%占空比的奇数分频
	parameter N = 7;
	
	reg [2:0] cnt;
	reg	clk_p;
	reg	clk_n;
	
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			cnt <= 3'd0;
		else if (cnt == (N-1))
			cnt <= 3'd0;
		else
			cnt <= cnt + 1'b1;
			
	always @(posedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_p <=1'b0;
		else if (cnt == (N-1)/2)
			clk_p <= ~clk_p;
		else if (cnt == 3'b0)
			clk_p <= ~clk_p;
		else
			clk_p <= clk_p;
			
	//将clk_p打半拍得到clk_n
	always @(negedge clk_in or negedge rst_n)
		if (!rst_n)
			clk_n <=1'b0;
		else
			clk_n <= clk_p;
			
	assign clk_out = clk_p | clk_n;

(3)利用基本逻辑单元直接搭建占空比为50%的奇数分频电路

  上面我们从波形生成方法及Verilog实现的角度思考了如何设计占空比为50%的奇数分频电路,这里我们直接从电路角度出发进行设计。首先思考如何用D触发器和组合逻辑实现占空比为50%的三分频电路?思路:先使用触发器构成序列生成器,输出001循环脉冲,实现占空比非50%的三分频,然后用负沿触发器打一拍,再相或。由于001循环共三个状态,故需2个D触发器。通过列状态表、画卡诺图,得到由两个D触发器及逻辑门构成的001序列生成器,后接负沿触发器打一拍并将其输出与序列生成器的输出相或,即得到占空比为50%的三分频电路。下面贴出三分频和五分频电路的简略设计思路及过程仅供参考,如图4、图5所示。

图4 三分频电路设计思路及过程

图5 五分频电路设计思路及过程

3、小数/分数分频

  小数分频电路可以转化为特定分频比电路设计问题。如19/9分频,意味着在输入时钟clk_in的19个周期内,输出需产生9个脉冲。因为19/9 = 2.11…, 因此可以用2分频和3分频配合实现,设待分频时钟的19个周期内共有x个二分频时钟周期,y个三分频时钟周期,则有:
x + y = 9 x+y=9 x+y=9
2 x + 3 y = 19 2x+3y=19 2x+3y=19
  解得 x = 8 , y = 1 x=8,y=1 x=8y=1。即只要在待分频时钟的19个周期内控制输出8个二分频时钟周期和1个三分频时钟周期即可。具体代码思路:

  1)首先一个总的计数器,在0-18循环;

  2)其次设计两个分别生成2分频和3分频的计数器,根据总计数器的数值范围分别在0-1和0-2循环;

  3)最后是波形生成逻辑,根据总计数器和2、3分频计数器的数值控制输出脉冲翻转生成期望分频比的时钟。

 reg [5:0] cnt;
	reg [3:0] cnt_a;
	reg [3:0] cnt_b;
	reg clk_out_reg;

	assign clk_out = clk_out_reg; 
	
	// div_a和div_b分别为根据文档公式计算出来的基准分频系数
	// change为2、3分频时钟的切换点
	parameter M = 5'd19;
	parameter change = 5'd16;
	parameter div_a = 5'd2;
	parameter div_b = 5'd3;
	
	//总计数器
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n)
			cnt <= 6'b0;
		else begin
			if(cnt == M - 1'b1)
				cnt <= 6'b0;
			else
				cnt <= cnt + 1'b1;
		end 

	
	//产生2、3分频的计数器
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n) begin
			cnt_a <= 4'b0;
			cnt_b <= 4'b0;
		end 
		else if(cnt <= change - 1'b1) begin
			cnt_b <= 4'd0;
			if(cnt_a == div_a - 1'b1)
				cnt_a <= 4'd0;
			else
				cnt_a <= cnt_a + 1'b1;
		end 
		else if(cnt > change - 1'b1) begin
			cnt_a <= 4'd0;
			if(cnt_b == div_b - 1'b1)
				cnt_b <= 4'd0;
			else
				cnt_b <= cnt_b + 1'b1;
		end
	
	//输出时钟产生逻辑
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n)
			clk_out_reg <= 1'b0;
		else if(cnt < change) begin
			if(cnt_a == 4'd0 || cnt_a == div_a/2)
				clk_out_reg <= ~clk_out_reg;
			else
				clk_out_reg <= clk_out_reg;
		end 
		else if(cnt >= change) begin
			if(cnt_b == 4'd0 || cnt_b == (div_b - 1'b1)/2)
				clk_out_reg <= ~clk_out_reg;
			else
			clk_out_reg <= clk_out_reg;
		end 

  上面代码的后段3分频是占空比非50%的,若要实现占空比50%,我们同样可以采取打半拍的方式并通过逻辑运算获得。代码和仿真结果如下,为了更好提现,这里实现20/9分频,通过公式计算得出在20个待分频时钟周期内,应该产生7个二分频脉冲和2个三分频脉冲。工程为Dec_Freq_Div_M_N。

  reg [5:0] cnt;
	reg [3:0] cnt_a;
	reg [3:0] cnt_b;
	reg clk_out_p;
	reg clk_out_n;
	assign clk_out = (cnt <= change) ? clk_out_p : (clk_out_p | clk_out_n); //产生占空比为50%的时钟
	
	// div_a和div_b分别为根据文档公式计算出来的基准分频系数
	// change为2、3分频时钟的切换点
	parameter M = 5'd20;
	parameter change = 5'd14;
	parameter div_a = 5'd2;
	parameter div_b = 5'd3;
	
	//总计数器
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n)
			cnt <= 6'b0;
		else begin
			if(cnt == M - 1'b1)
				cnt <= 6'b0;
			else
				cnt <= cnt + 1'b1;
		end 

	
	//产生2、3分频的计数器
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n) begin
			cnt_a <= 4'b0;
			cnt_b <= 4'b0;
		end 
		else if(cnt <= change - 1'b1) begin
			cnt_b <= 4'd0;
			if(cnt_a == div_a - 1'b1)
				cnt_a <= 4'd0;
			else
				cnt_a <= cnt_a + 1'b1;
		end 
		else if(cnt > change - 1'b1) begin
			cnt_a <= 4'd0;
			if(cnt_b == div_b - 1'b1)
				cnt_b <= 4'd0;
			else
				cnt_b <= cnt_b + 1'b1;
		end
	
	//输出时钟产生逻辑
	always @(posedge clk_in or negedge rst_n) 
		if(!rst_n)
			clk_out_p <= 1'b0;
		else if(cnt < change) begin
			if(cnt_a == 4'd0 || cnt_a == div_a/2)
				clk_out_p <= ~clk_out_p;
			else
				clk_out_p <= clk_out_p;
		end 
		else if(cnt >= change) begin
			if(cnt_b == 4'd0 || cnt_b == (div_b - 1'b1)/2)
				clk_out_p <= ~clk_out_p;
			else
			clk_out_p <= clk_out_p;
		end 
	//打半拍
		always @(negedge clk_in or negedge rst_n)
			if(!rst_n)
				clk_out_n <= 1'b0;
			else
				clk_out_n <= clk_out_p;

下图是本文的文件截图,有需要的话点击下面的链接获取:

FPGA完整工程和源码分享,点此跳转获取完整工程和源码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xxqlover/article/details/137999398

智能推荐

尚硅谷_谷粒学苑-微服务+全栈在线教育实战项目之旅_基于微服务的在线教育平台尚硅谷-程序员宅基地

文章浏览阅读2.7k次,点赞3次,收藏11次。SpringBoot+Maven+MabatisPlusmaven在新建springboot项目引入RELEASE版本出错maven在新建springboot项目引入RELEASE版本出错maven详解maven就是通过pom.xml中的配置,就能够从仓库获取到想要的jar包。仓库分为:本地仓库、第三方仓库(私服)、中央仓库springframework.boot:spring-boot-starter-parent:2.2.1.RELEASE’ not found若出现jar包下载不了只有两_基于微服务的在线教育平台尚硅谷

java 实现 数据库备份_java数据备份-程序员宅基地

文章浏览阅读1k次。数据库备份的方法第一种:使用mysqldump结合exec函数进行数据库备份操作。第二种:使用php+mysql+header函数进行数据库备份和下载操作。下面 java 实现数据库备份的方法就是第一种首先我们得知道一些mysqldump的数据库备份语句备份一个数据库格式:mysqldump -h主机名 -P端口 -u用户名 -p密码 --database 数据库名 ..._java数据备份

window10_ffmpeg调试环境搭建-编译64位_win10如何使用mingw64编译ffmpeg-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏14次。window10_ffmpeg调试环境搭建_win10如何使用mingw64编译ffmpeg

《考试脑科学》_考试脑科学pdf百度网盘下载-程序员宅基地

文章浏览阅读6.3k次,点赞9次,收藏14次。给大家推荐《考试脑科学》这本书。作者介绍:池谷裕二,日本东京大学药学系研究科教授,脑科学研究者。1970年生于日本静冈县,1998年取得日本东京大学药学博士学位,2002年起担任美国哥伦比亚大学客座研究员。专业为神经科学与药理学,研究领域为人脑海马体与大脑皮质层的可塑性。现为东京大学药学研究所教授,同时担任日本脑信息通信融合研究中心研究主任,日本药理学会学术评议员、ERATO人脑与AI融合项目负责人。2008年获得日本文部大臣表彰青年科学家奖,2013年获得日本学士院学术奖励奖。这本书作者用非常通俗易懂_考试脑科学pdf百度网盘下载

今天给大家介绍一下华为智选手机与华为手机的区别_华为智选手机和华为手机的区别-程序员宅基地

文章浏览阅读1.4k次。其中,成都鼎桥通信技术有限公司是一家专业从事移动通讯终端产品研发和生产的高科技企业,其发布的TD Tech M40也是华为智选手机系列中的重要代表之一。华为智选手机是由华为品牌方与其他公司合作推出的手机产品,虽然其机身上没有“华为”标识,但是其品质和技术水平都是由华为来保证的。总之,华为智选手机是由华为品牌方和其他公司合作推出的手机产品,虽然外观上没有“华为”标识,但其品质和技术水平都是由华为来保证的。华为智选手机采用了多种处理器品牌,以满足不同用户的需求,同时也可以享受到华为全国联保的服务。_华为智选手机和华为手机的区别

c++求n个数中的最大值_n个数中最大的那个数在哪里?输出其位置,若有多个最大数则都要输出。-程序员宅基地

文章浏览阅读7.6k次,点赞6次,收藏17次。目录题目描述输入输出代码打擂法数组排序任意输入n个整数,把它们的最大值求出来.输入只有一行,包括一个整数n(1_n个数中最大的那个数在哪里?输出其位置,若有多个最大数则都要输出。

随便推点

Linux常用命令_ls-lmore-程序员宅基地

文章浏览阅读4.8k次,点赞17次,收藏51次。Linux的命令有几百个,对程序员来说,常用的并不多,考虑各位是初学者,先学习本章节前15个命令就可以了,其它的命令以后用到的时候再学习。1、开机 物理机服务器,按下电源开关,就像windows开机一样。 在VMware中点击“开启此虚拟机”。2、登录 启动完成后,输入用户名和密码,一般情况下,不要用root用户..._ls-lmore

MySQL基础命令_mysql -u user-程序员宅基地

文章浏览阅读4.1k次。1.登录MYSQL系统命令打开DOS命令框shengfen,以管理员的身份运行命令1:mysql -u usernae -p password命令2:mysql -u username -p password -h 需要连接的mysql主机名(localhost本地主机名)或是mysql的ip地址(默认为:127.0.0.1)-P 端口号(默认:3306端口)使用其中任意一个就OK,输入命令后DOS命令框得到mysql>就说明已经进入了mysql系统2. 查看mysql当中的._mysql -u user

LVS+Keepalived使用总结_this is the redundant configuration for lvs + keep-程序员宅基地

文章浏览阅读484次。一、lvs简介和推荐阅读的资料二、lvs和keepalived的安装三、LVS VS/DR模式搭建四、LVS VS/TUN模式搭建五、LVS VS/NAT模式搭建六、keepalived多种real server健康检测实例七、lvs持久性工作原理和配置八、lvs数据监控九、lvs+keepalived故障排除一、LVS简介和推荐阅读的资料 学习LVS+Keepalived必须阅读的三个文档。1、 《Keepalived权威指南》下载见http://..._this is the redundant configuration for lvs + keepalived server itself

Android面试官,面试时总喜欢挖基础坑,整理了26道面试题牢固你基础!(3)-程序员宅基地

文章浏览阅读795次,点赞20次,收藏15次。AIDL是使用bind机制来工作。java原生参数Stringparcelablelist & map 元素 需要支持AIDL其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。下图是我进阶学习所积累的历年腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

机器学习-数学基础02补充_李孟_新浪博客-程序员宅基地

文章浏览阅读248次。承接:数据基础02

短沟道效应 & 窄宽度效应 short channel effects & narrow width effects-程序员宅基地

文章浏览阅读2.8w次,点赞14次,收藏88次。文章目录1. 概念:Narrow Width Effect: 窄宽度效应Short Channel effects:短沟道效应阈值电压 (Threshold voltage)2. 阈值电压与沟道长和沟道宽的关系:Narrow channel 窄沟的分析Short channel 短沟的分析1. 概念:Narrow Width Effect: 窄宽度效应在CMOS器件工艺中,器件的阈值电压Vth 随着沟道宽度的变窄而增大,即窄宽度效应;目前,由于浅沟道隔离工艺的应用,器件的阈值电压 Vth 随着沟道宽度_短沟道效应