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

        分频器是数字系统中最常见的基本电路之一。分频就是将输入信号的频率变成成倍地低于输入频率的输出信号。如输入信号频率为50MHZ,10分频后输出信号频率为5MHZ。这里10是分频系数,分频系数为偶数则为偶分频,分频系数为奇数则为奇分频。

        分频有两种方式:一是通过HDL语言建模产生所需要的时钟信号,二是利用开发工具的PLL进行分频。前者分频灵活,需编写代码实现;后者使用场景受限,因为有的低端FPGA没有PLL,但PLL的分频效果更好,而且在进行小数分频时也比较容易实现。

1、偶分频

        以6分频为例,有两种方法:分频法和降频法。

①分频法

        分频系数为N(N为偶数),就是N分频,分频器实现方法和计数器原理一致,当计数值到(N/2)-1时,输出信号电平翻转,此输出信号即为N分频的信号。

module divider_six
(
	input	wire	sys_clk,
	input	wire	sys_rst_n,
	output	reg		clk_out
);

reg	[1:0] cnt;

always@(posedge sys_clk or negedge sys_rst_n)
	begin
	if(sys_rst_n == 1'b0)
		cnt <= 2'b0;
	else if(cnt == 2'd2)
		cnt <= 2'b0;
	else
		cnt <= cnt + 1'b1;
	end
always@(posedge sys_clk or negedge sys_rst_n)
	begin
	if(sys_rst_n == 1'b0)
		clk_out <=	1'b0;
	else if(cnt == 2'd2)
		clk_out <= ~clk_out;
	else
		clk_out <= clk_out;
	end
endmodule
`timescale 1ns/1ns
module tb_divider_six();

reg sys_clk;
reg sys_rst_n;

wire clk_out;

initial
	begin
		sys_clk = 1'b1;
		sys_rst_n = 1'b0;
		#20
		sys_rst_n = 1'b1;
	end

always #10 sys_clk = ~sys_clk;

divider_six divider_six_inst
(
		.sys_clk	(sys_clk),
		.sys_rst_n  (sys_rst_n),
		.clk_out    (clk_out)
);		

endmodule

        上述方法生成了低频时钟clk_out,但是如果直接用clk_out作为驱动时钟实现一些功能会出现隐患。在FPGA中凡是时钟信号都需要连接到全局时钟网络(全局时钟树),是FPGA厂商专门为时钟路径设计的,它能使时钟信号到达每个寄存器的时间尽可能地相同,减少时序问题的产生。而分频方式产生的低频时钟并没有连接到全局时钟网络上,外部晶振产生的时钟信号通过管脚连接到FPGA专用的时钟引脚上,即连接到了全局时钟网络上。所以在系统时钟控制下的信号比低频时钟控制下的信号更能保持稳定。

②降频法

        下面采用生成标志位(脉冲标志信号clk_flag)对上述方法进行一些改进。在计数值达到N-2(这里N-2为4,用N-2是因为时序逻辑生成信号会延迟一个周期)时,生成一个脉冲标志信号clk_flag,并保持一个时钟周期。如此仍用系统时钟作为驱动时钟,而将clk_flag作为标志信号进行条件判断,可以实现和上述方法相同的分频功能。运用标志信号的方法在高速系统中能够减少时序错误,这种方法称之为降频。

module divider_six
(
	input	wire	sys_clk,
	input	wire	sys_rst_n,
	output	reg		clk_flag
);

reg	[2:0] cnt;
always@(posedge sys_clk or negedge sys_rst_n)
	begin
	if(sys_rst_n == 1'b0)
		cnt <= 3'b0;
	else if(cnt == 3'd5)
		cnt <= 3'b0;
	else
		cnt <= cnt + 1'b1;
	end
	
always@(posedge sys_clk or negedge sys_rst_n)
	begin
	if(sys_rst_n == 1'b0)
		clk_flag <= 3'b0;
	else if(cnt ==  3'd4)
		clk_flag <= 1'b1;
	else
		clk_flag <= 1'b0;
	end

endmodule
`timescale 1ns/1ns
module tb_divide_six();

reg sys_clk;
reg sys_rst_n;

wire clk_flag;

initial
	begin
		sys_clk = 1'b1;
		sys_rst_n = 1'b0;
		#20
		sys_rst_n = 1'b1;
	end

always #10 sys_clk = ~sys_clk;

divide_six divide_six_inst
(
		.sys_clk	(sys_clk),
		.sys_rst_n  (sys_rst_n),
		.clk_flag   (clk_flag)
);		

endmodule

总结:在高速系统用到分频时钟的时候,最好采用生成脉冲标志信号的方法,可减少时序错误。低速系统中甚至只有几个寄存器的情况下,采用两种方法皆可。

2、奇分频

        以5分频为例,有两种方法:分频法和降频法。

 ①分频法

        只需(clk_1 | clk_2)即可得到占空比为50%的clk_out。

module divider_five
(
	input	wire	sys_clk,
	input	wire	sys_rst_n,
	output	wire	clk_out
);

	reg	[2:0]	cnt;
	reg	clk_1;
	reg	clk_2;
	
always@(posedge sys_clk or negedge sys_rst_n)
begin
	if(sys_rst_n == 1'b0)
		cnt <= 3'd0;
	else if(cnt == 3'd4)
		cnt <= 3'd0;
	else
		cnt <= cnt + 1'b1;
end
	
always@(posedge sys_clk or negedge sys_rst_n)
begin
	if(sys_rst_n == 1'b0)
		clk_1 <= 1'd0;
	else if(cnt == 3'd2)
		clk_1 <= 1'b1;
	else if(cnt == 3'd4)
		clk_1 <= 1'b0;
	else
		clk_1 <= clk_1;
end

always@(negedge sys_clk or negedge sys_rst_n)
begin
	if(sys_rst_n == 1'b0)
		clk_2 <= 1'b0;
	else if(cnt == 3'd2)
		clk_2 <= 1'b1;
	else if(cnt == 3'd4)
		clk_2 <= 1'b0;
	else
		clk_2 <= clk_2;
end
assign clk_out = (clk_1 | clk_2);

endmodule
`timescale 1ns/1ns
module tb_divider_five();

reg sys_clk;
reg sys_rst_n;

wire clk_out;

initial
	begin
		sys_clk = 1'b1;
		sys_rst_n = 1'b0;
		#20
		sys_rst_n = 1'b1;
	end

always #10 sys_clk = ~sys_clk;

divider_five divider_five_inst
(
		.sys_clk	(sys_clk),
		.sys_rst_n  (sys_rst_n),
		.clk_out   (clk_out)
);		

endmodule

 ②降频法

module divider_five
(
	input	wire	sys_clk,
	input	wire	sys_rst_n,
	output	reg		clk_flag
);

	reg	[2:0]	cnt;
	
always@(posedge sys_clk or negedge sys_rst_n)
begin
	if(sys_rst_n == 1'b0)
		cnt <= 3'd0;
	else if(cnt == 3'd4)
		cnt <= 3'd0;
	else
		cnt <= cnt + 1'b1;
end
always@(posedge sys_clk or negedge sys_rst_n)
begin
	if(sys_rst_n == 1'b0)
		clk_flag <= 3'd0;
	else if(cnt == 3'd3)
		clk_flag <= 3'd1;
	else
		clk_flag <= 1'b0;
end
	
endmodule
`timescale 1ns/1ns
module tb_divider_five();

reg sys_clk;
reg sys_rst_n;

wire clk_flag;

initial
	begin
		sys_clk = 1'b1;
		sys_rst_n = 1'b0;
		#20
		sys_rst_n = 1'b1;
	end

always #10 sys_clk = ~sys_clk;

divider_five divider_five_inst
(
		.sys_clk	(sys_clk),
		.sys_rst_n  (sys_rst_n),
		.clk_flag   (clk_flag)
);		

endmodule

  • 6
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

发光中请勿扰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值