Verilog手撕代码(6)分频器

这篇具有很好参考价值的文章主要介绍了Verilog手撕代码(6)分频器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

分频概念

分频就是生成一个新时钟,该新时钟的频率是原有时钟频率的整数分之一倍,新周期是原有周期的整数倍。

再简单来说,让你手撕一个四分频电路,就是写代码生成一个周期是原来四倍的时钟,如果手撕一个三分频电路,就是写代码生成一个周期是原来三倍的时钟。
分频器verilog,# Verilog手撕代码,fpga开发
如图为四分频波形图,clk_out的频率是clk的1/4,但周期是clk的4倍。
分频主要分为偶数分频、奇数分频、小数分频。

偶数分频

二分频

二分频引入,在每个时钟上升沿来到时,翻转新时钟

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_2 <= 0;
	else
		clk_2 <= ~clk_2;
end

得到的结果如下:
分频器verilog,# Verilog手撕代码,fpga开发

任意偶数

代码:

module div
#(
	parameter num = 8
)
(
	input clk,
	input rst_n,
	output reg clk_out
);


reg [2:0]cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt <= 0;
		clk_out <= 0;
	end
	else if(cnt == num/2 -1)begin
		cnt <= 0;
		clk_out <= ~clk_out; 
	end	
	else
		cnt <= cnt + 1'b1;
end

endmodule

Testbench

module div_tb();
	reg clk;
	reg rst_n;
	wire clk_out;
	
	div u0(
		.clk(clk),
		.rst_n(rst_n),
		.clk_out(clk_out)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#15 
		rst_n = 1;
		
		#50000
		$stop;
	
	end
	
endmodule

仿真结果:
分频器verilog,# Verilog手撕代码,fpga开发

每4各clk,clk_out翻转一次,即8个clk周期的为clk_out的一个周期。

在Testbench中使用defparam语句覆盖原始rtl中的num初始值,改为4分频。

defparam num = 4;

结果为:
分频器verilog,# Verilog手撕代码,fpga开发

占空比问题

上面写的任意偶数分频代码的占空比都是50%,实际上面试手撕代码不会让你50%占空比

方法:==进行计数,对于一个八分频,开始就把时钟设为高电平,我用cnt 计数到两个时钟上升沿后再把它拉低,计数到7后cnt 拉低 时钟拉高,这样就实现了两个周期高,六个周期低,占空比为2/8 即 25% 的八分频。 ==

奇分频

任意奇数分频代码:

module div_2
#(
	parameter N = 7
)
(
	input clk,
	input rst_n,
	output reg clk_out
);

reg [2:0] cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 3'd0;
	else 
		cnt <= (cnt == (N-1))?3'd0:cnt + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_out <= 1'b0;
	else if((cnt == N-1)|(cnt == (N-1)/2))
		clk_out <= ~clk_out;
	else
		clk_out <= clk_out;
end

endmodule

Testbench:

`timescale 1ns/1ns
module div_2_tb();
	reg clk;
	reg rst_n;
	wire clk_out;
	
	div_2 inst(
		.clk(clk),
		.rst_n(rst_n),
		.clk_out(clk_out)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#15
		rst_n = 1;
		#3000
		$stop;
	end
endmodule

仿真结果:
分频器verilog,# Verilog手撕代码,fpga开发

在cnt = 4 和cnt = 6的时候对clk_out翻转,可以看到每经过7个clk,生成一个clk_out完整周期。但是计算clk_out的占空比可得为3/7,并不是规整的50%占空比。

实现50%占空代码:

module div_2
#(
	parameter N = 7
)
(
	input clk,
	input rst_n,
	output wire clk_out
);

reg [2:0] cnt_pos;
reg [2:0] cnt_neg;
reg clk_pos,clk_neg;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt_pos <= 3'd0;
	else 
		cnt_pos <= (cnt_pos == (N-1))?3'd0:cnt_pos + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_pos <= 1'b0;
	else if((cnt_pos == N-1)|(cnt_pos == (N-1)/2))
		clk_pos <= ~clk_pos;
	else
		clk_pos <= clk_pos;
end

always@(negedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt_neg <= 3'd0;
	else 
		cnt_neg  <= (cnt_neg  == (N-1))?3'd0:cnt_neg  + 1'd1;
end

always@(negedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_neg <= 1'b0;
	else if((cnt_neg == N-1)|(cnt_neg == (N-1)/2))
		clk_neg <= ~clk_neg;
	else
		clk_neg <= clk_neg;
end

assign clk_out = clk_pos | clk_neg;

endmodule

Testbench:

`timescale 1ns/1ns
module div_2_tb();
	reg clk;
	reg rst_n;
	wire clk_out;
	
	div_2 inst(
		.clk(clk),
		.rst_n(rst_n),
		.clk_out(clk_out)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#15
		rst_n = 1;
		#3000
		$stop;
	end
endmodule

仿真结果:
分频器verilog,# Verilog手撕代码,fpga开发

非常规占空比的奇分频

非常规占空比的奇数分频器,比如 3/10占空比的五分频, 5/18占空比的九分频?

与上面实现50%任意奇数分频器的原理是类似的,但是采用与运算。用占空比为 2/5 上升沿采样的信号和 2/5占空比下降沿采样的信号相与。

所以相与后,占空比就为 2/5 - 1/10 = 3/10 ,示意图如下:
分频器verilog,# Verilog手撕代码,fpga开发

5/18占空比的九分频就是用上升沿采样的3/9占空比九分频 和下降沿采样的3/9占空比九分频相与,最后结果为3/9-1/18 = 5/18 占空比。具体修改只需要改cnt判断数值以及把clk_out 的赋值从clk_out1,clk_out2相或改成相与。

代码参考:verilog代码

分频时钟的使用

在其他模块利用分频时钟时,分频得到的时钟并未连接到FPGA内部的全局时钟树,因此使用分频时钟的模块与其他使用系统时钟clk的模块存在时钟到达时间的偏差,而在设计过程中,我们希望的使各个模块的时钟达到时间使相近的,减少时序问题。

在一些低速系统或模块中,使用分频时钟出现问题的概率较低,但在高速系统和模块中,使用分频时钟就会容易出现问题,导致各模块的时钟到达时间存在较大的偏差,为解决这个问题,分频时生成脉冲时钟。
以7分频为例:

module div_3
#(
	parameter N = 7
)
(
	input clk,
	input rst_n,
	output reg clk_flag
);

reg [2:0] cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 3'd0;
	else 
		cnt <= (cnt == (N-1))?3'd0:cnt + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_flag <= 1'b0;
	else if(cnt == N-2)
		clk_flag <= 1'b1;
	else
		clk_flag <= 1'b0;
end

endmodule

Testbench与上面一样

`timescale 1ns/1ns
module div_3_tb();
	reg clk;
	reg rst_n;
	wire clk_flag;
	
	div_3 inst(
		.clk(clk),
		.rst_n(rst_n),
		.clk_flag(clk_flag)
	);

	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#15
		rst_n = 1;
		#3000
		$stop;
	end
endmodule

仿真结果:
分频器verilog,# Verilog手撕代码,fpga开发
在Testbench中利用defparam对N进行修改,改为4分频

	defparam inst.N = 4;

分频器verilog,# Verilog手撕代码,fpga开发
由此,在利用分频后的脉冲信号clk_flag 进行判断和处理,例如:

module div_3
#(
	parameter N = 7
)
(
	input clk,
	input rst_n,
	output reg clk_out,
	output reg clk_flag
);

reg [2:0] cnt;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 3'd0;
	else 
		cnt <= (cnt == (N-1))?3'd0:cnt + 1'd1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_out <= 1'b0;
	else if((cnt == N-1)|(cnt == (N-1)/2))
		clk_out <= ~clk_out;
	else
		clk_out <= clk_out;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		clk_flag <= 1'b0;
	else if(cnt == N-2)
		clk_flag <= 1'b1;
	else
		clk_flag <= 1'b0;
end
reg [2:0] a,b;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		a <= 3'b0;
	else if(clk_flag == 1)
		a <= a + 1'b1;
end

always@(posedge clk_out or negedge rst_n)begin
	if(!rst_n)
		b <= 3'b0;
	else 
		b <= a + 1'b1;
end

endmodule

其中a计数器是由clk_flag控制的,b计数器是由clk_out控制的,而本质上clk_flag是由系统时钟clk进行控制的,因此a由系统时钟clk控制,与其他采用系统时钟clk的模块都保持着相同的时钟关系,b由clk_out控制,与系统时钟clk存在一定的偏差,因此推荐使用脉冲信号的写法。

本质上来说,脉冲信号clk_flag是降频写法,无法对占空比进行设计,clk_out是分频写法,达到的效果是一样的,但在时序问题上,脉冲信号clk_flag写法更好!

小数分频

编码小数分频,就不能看微观了,要用宏观的眼界去看,比如实现一个 17/3 分频,表达成:17 除以 3 得商为 5 余2。
那么我们就可以通过5(商)分频和7(商+余数)来实现 17/3 分频。
确定5分频和7分频的次数,设:5分频的次数为a , 7分频的次数为b,那么应该有:

 a+b=3(除数)
 5a+7b = 17(被除数)

得a=2,b=1,也就是说通过2次5分频和1次7分频可得到 17/3 分频。
宏观来看,总共是17个时钟周期,由三个分频器均分,那么平均每个分频器就是分到17/3了,这就是小数分频,这是一个宏观的平均概念。
代码:

module div_M_N(
	input clk,
	input rst_n,
	output reg clk_out
);
reg [4:0] cnt;
reg [2:0] cnt1;
reg [2:0] cnt2;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 5'd0;
	else 
		cnt <= (cnt == 5'd16)?5'd0:cnt + 1'b1;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt1 <= 3'd0;
		cnt2 <= 3'd0;
		clk_out <= 1'b0;
	end
	else if(cnt < 5'd10)begin //cnt<5'd10中包含两个5分频。占空比为1/5
		if(cnt1 == 3'd4)begin
			cnt1 <= 3'd0;
			clk_out <= 1'b1;
		end
		else if(cnt1 == 3'd0)begin
			cnt1 <= cnt1 + 1'b1;
			clk_out <= 1'b0;
		end
		else begin
			cnt1 <= cnt1 + 1'b1;
		end		
	end
	else begin                   //5'd10=<cnt<=5'd17中包含一个7分频。占空比为1/5
		if(cnt2 == 3'd6)begin
			cnt2 <= 3'd0;
			clk_out <= 1'b1;
		end
		else if(cnt2 == 3'd0)begin
			cnt2 <= cnt2 + 1'b1;
			clk_out <= 1'd0;
		end
		else begin
			cnt2 <= cnt2 + 1'b1;
		end
	end	
end

endmodule

Testbench:

module div_M_N_tb();
	reg clk;
	reg rst_n;
	wire clk_out;

	div_M_N inst(
		.clk(clk),
		.rst_n(rst_n),
		.clk_out(clk_out)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#20
		rst_n = 1;
		#5000
		$stop;		
	end
endmodule

仿真结果:
分频器verilog,# Verilog手撕代码,fpga开发
可以看出,两个五分频,一个七分频,每十七个周期循环一次。即每十七个周期有三个分频器,平摊下来就是 17/3 。
小数分频的缺点就是 占空比不为50%,要想实现50%占空比的小数分频,涉及很多算法,具体算法十分复杂。

可参考:任意小数分频(50%占空比)

分频器verilog,# Verilog手撕代码,fpga开发

8.7分频verilog代码:

module div_M_N_2(
	input clk,
	input rst_n,
	output clk_out
);

parameter M_N = 8'd87;  //总周期
parameter c89 = 8'd24;	//8分频9分频切换点
parameter div_e = 5'd8;	//偶分频周期
parameter div_o = 5'd9;	//奇分频周期

reg [7:0] cnt;
reg [3:0] cnt_8;
reg [3:0] cnt_9;
reg clk_out_r;

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		cnt <= 8'd0;
	else if(cnt == M_N - 1)
		cnt <= 8'd0;
	else
		cnt <= cnt + 1'b1;
end

reg div_flag;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		div_flag <= 1'b0;
	else if((cnt == (M_N -1)) | (cnt ==  (c89 - 1)))
		div_flag <= ~div_flag;
	else 
		div_flag <= div_flag;
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_8 <= 3'd0;
		cnt_9 <= 4'd0;
	end
	else if(div_flag == 0)begin
		cnt_8 <= (cnt_8 == (div_e - 1))?0:cnt_8 + 1'b1;
	end
	else if(div_flag == 1)begin
		cnt_9 <= (cnt_9 == (div_o - 1))?0:cnt_9 + 1'b1;
	end
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)	
		clk_out_r <= 1'b0;
	else if( ((cnt_8 == 4 | cnt_8 == 0)&&(div_flag == 0)) | ( (cnt_9 == 0 | cnt_9 == 4)&&(div_flag == 1 )) )
		clk_out_r <= ~clk_out_r;
end

assign clk_out = clk_out_r;

endmodule	

Testbeench:

module div_M_N_tb();
	reg clk;
	reg rst_n;
	wire clk_out;

	div_M_N_2 inst(
		.clk(clk),
		.rst_n(rst_n),
		.clk_out(clk_out)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		#20
		rst_n = 1;
		#5000
		$stop;		
	end
endmodule

仿真结果:

分频器verilog,# Verilog手撕代码,fpga开发文章来源地址https://www.toymoban.com/news/detail-715244.html

到了这里,关于Verilog手撕代码(6)分频器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数字分频器设计(偶数分频、奇数分频、小数分频、半整数分频、状态机分频|verilog代码|Testbench|仿真结果)

    数字IC经典电路设计 经典电路设计是数字IC设计里基础中的基础,盖大房子的第一部是打造结实可靠的地基,每一篇笔者都会分门别类给出设计原理、设计方法、verilog代码、Testbench、仿真波形。然而实际的数字IC设计过程中考虑的问题远多于此,通过本系列希望大家对数字I

    2024年02月08日
    浏览(44)
  • 【FPGA】Verilog:时序电路设计 | 二进制计数器 | 计数器 | 分频器 | 时序约束

    前言: 本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例:计数器与分频器   ​​ 功能特性: 采用 Xilinx Artix-7 XC7A35T芯片  配置方式:USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度  存储器:2Mbit SRAM   N25Q064A SPI Flash(样图旧款为N25Q032A) 通用

    2024年02月02日
    浏览(61)
  • verilog---分频器设计

    //设计分频器 将50MHZ信号分频产生1HZ的秒脉冲,输出信号占空比为50%。 //设计思路:用计数器设计,N分频:当计数到(N/2)-1个数时,输出时钟翻转一次 //50*10^6次分频:计数到24 999 999(需要25bit)时,输出信号翻转。 //无法用vmf仿真,因为endtime最大为10us,实际最少需要1000000u

    2024年02月04日
    浏览(35)
  • 【实验室学习】时钟分频器,2、3、4、8分频 verilog实现

    记录时钟分频器的Verilog代码编写,主要掌握分频器设计思路 2、4、8分频设计较为容易: 2分频—设计一个1位的寄存器,当原时钟上升沿时取反即可 代码展示: 4分频与8分频—设计一个两位的计数器,4分频只需在计数器计数到00B或者10B时跳变电平即可,8分频只需在计数器计

    2024年02月11日
    浏览(43)
  • FPGA设计开发(基础课题):分频器设计

    一、设计目的 1、掌握分频器的设计原理; 2、用HDL语言设计分频器。 二、设计原理 分频器与计数器类似,也是要对时钟脉冲进行计数,但其输出的不是对时钟脉冲个数的计数值,而是其频率与时钟的频率成固定比例关系的脉冲信号。整数分频是所有分频器中最简单,最容易

    2024年02月13日
    浏览(53)
  • FPGA学习——实现任意倍分频器(奇数/偶数倍分频器均可实现)

    在FPGA(可编程逻辑门阵列)中,分频器是一种用于将时钟信号的频率降低的电路或模块。它可以根据输入的时钟信号生成一个较低频率的输出时钟信号。 常见的分频器可以按照固定比例来进行分频,例如将输入时钟频率除以2、除以4等。因此,如果输入时钟信号的频率为10

    2024年02月05日
    浏览(41)
  • FPGA——分频器

    野火学习备忘录——FPAG分频 时钟对于 FPGA 是非常重要的,但板载晶振提供的时钟信号频率是固定的,不一定满 足工程需求,所以分频和倍频还是很有必要的。这里通过计数的方式来实现分频。 1.通过计数器来实现6分频。两种方式。第一种直接通过计数方式直接获取获取。输

    2024年02月10日
    浏览(42)
  • FPGA 多路分频器实验

    1 概述         在 FPGA 中,时钟分频是经常用到的。本节课讲解 2 分频、3 分频、4 分频和 8 分频的 Verilog 实现并且学习 generate 语法功能的应。 2 程序设计思路         1)整数倍分频,为 2、4、8,这种 2^n 次方倍数倍数关系的分频最容易实现,所以我们可以把这 3 种分

    2024年01月19日
    浏览(37)
  • FPGA基础设计(二):任意分频器(奇数,偶数,小数)

    FPGA开发板上一般只有一个晶振,即一种时钟频率。数字系统设计中,时间的计算都要以时钟作为基本单元,对基准时钟进行不同倍数的分频而得到各模块所需时钟频率,可通过Verilog代码实现;倍频可通过锁相环【PLL】实现。 把输入信号的频率变成成倍的低于输入频率的输出

    2024年02月01日
    浏览(41)
  • 实验二 基于FPGA的分频器的设计(基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。拓展任务1:用按键或开关控制蜂鸣器的响与不响。拓展任务2:用按键或开)

    1. 实验目的: (1) 掌握QuartusⅡ软件的层次型设计方法; (2) 掌握元件封装及调用方法; (3) 熟悉FPGA实验平台,掌握引脚锁定及下载。 2. 实验任务: (1) 基本任务:设计一个分频器,输入信号50MHz,输出信号频率分别为1KHz、500Hz及1Hz。 (2) 拓展任务1:用按键或开关

    2024年02月06日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包