verilog实现时钟的任意整数分频电路

关于时钟的分频,博主曾经分享过相关的文章,FPGA 实现任意分频系数和占空比的时钟输出。本篇文章将从另一个角度实现时钟的奇分频和偶分频,占空比为 50%。

偶分频

6 分频为例。

偶分频是最简单的,通过下图就可以很好的理解,其中只需要两个 always 块,其中一个用来计数,计数器每次计数到 5,然后清零重新计数,第二个 always 块用来产生分频时钟,假设初始状态为高电平,当计数到 2 时,将信号拉低,当计数到 5 时,将信号拉高。

verilog实现时钟的任意整数分频电路

那么对于任意的偶分频,如何确定 cnt 的最大值,如何确定 div_clk 信号什么时候拉低,什么时候拉高呢,通过 6 分频的分析,我们看到,当 cnt 计数到 6-1 时,给 cnt 信号清零,并且当 cnt=6-1 时将 div_clk 拉高,当计数到(6-1)/2 时,将 div_clk 拉低。因此,假设现在要进行 n 分频,n 为偶数,则 cnt 的最大值为 n-1,当 cnt 计数到 n-1 时,将 div_clk 拉高,当 cnt 计数到(n-1)/2 时,将 div_clk 拉低。

代码如下:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dongtaolv
// Email  : tdlv@stu.xidian.edu.cn 
// File   : even_divider.v
// Create : 2021-04-26 19:59:35
// Revise : 2021-04-26 19:59:35
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module even_divider #(
	parameter DIVIDER_NUMBER = 6
)(
	input	wire	clk,
	input	wire	rst,
	output	wire	div_clk
);

reg	[3:0]	cnt;           //当分频数大于 15 时,此值的位数需要扩展
reg			div_clk_r;

assign div_clk = div_clk_r;

always @(posedge clk)begin
	if(rst)begin
		cnt <= 'd0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end

always @(posedge clk)begin
	if(rst)begin
		div_clk_r <= 1'b1;
	end
	else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin
		div_clk_r <= 1'b0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		div_clk_r <= 1'b1;
	end
end

endmodule

6 分频仿真如下:

verilog实现时钟的任意整数分频电路

奇分频

奇分频相对于偶分频来说比较复杂,我们首先给出 5 分频的图。

verilog实现时钟的任意整数分频电路

其中 div_clk 信号就是我们的 5 分频产生的时钟,我们可以看到,这需要在系统时钟 clk 的上升沿和下降沿都工作,所以,我们使用三个 always 块。

其中,一个 always 块和偶分频一样,用来产生计数器 cnt,这个计数器在 clk 的上升沿计数,每次计数到 4 时清零。

第二个 always 块用来产生 clk,初始为高电平,该信号在 clk 的上升沿产生,当 cnt 计数到 2 时,将 clk1 信号拉低,当计数到 4 时,将 clk1 信号拉高,这个信号和偶分频产生类似。

第三个 always 块就有区别了,他是通过 clk 的下降沿来产生的,也就是图中的 clk2 信号,初始状态为高电平,当 cnt 计数到 2 并且 clk 的下降沿到来时,我们将 clk2 信号拉低,当 cnt 计数到 4 并且 clk 的下降沿到来时,我们将 clk2 信号拉高。

最后得到的分频时钟 div_clk 可以通过组合逻辑得到,我们直接将 clk1 和 clk2 求与运算就可以得到 div_clk 信号。

代码如下:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dongtaolv
// Email  : tdlv@stu.xidian.edu.cn 
// File   : odd_divider.v
// Create : 2021-04-26 19:59:35
// Revise : 2021-04-26 19:59:35
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module odd_divider #(
	parameter DIVIDER_NUMBER = 5
)(
	input	wire	clk,
	input	wire	rst,
	output	wire	div_clk
);

reg	[3:0]	cnt;           //当分频数大于 15 时,此值的位数需要扩展

reg			clk1;
reg			clk2;

always @(posedge clk)begin
	if(rst)begin
		cnt <= 'd0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end

always @(posedge clk)begin
	if(rst)begin
		clk1 <= 1'b1;
	end
	else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin
		clk1 <= 1'b0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		clk1 <= 1'b1;
	end
end

always @(negedge clk)begin
	if(rst)begin
		clk2 <= 1'b1;
	end
	else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin
		clk2 <= 1'b0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		clk2 <= 1'b1;
	end
end

assign div_clk = clk1 && clk2;

endmodule

5 分频仿真如下:

verilog实现时钟的任意整数分频电路

任意分频

在知道如何任意奇分频和任意偶分频之后,只需要将两个结合就可以得到任意整数分频,具体代码如下:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dongtaolv
// Email  : tdlv@stu.xidian.edu.cn 
// File   : random_divider.v
// Create : 2021-04-26 19:59:35
// Revise : 2021-04-26 19:59:35
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------
module random_divider #(
	parameter DIVIDER_NUMBER = 5
)(
	input	wire	clk,
	input	wire	rst,
	output	wire	div_clk
);

reg	[3:0]	cnt;           //当分频数大于 15 时,此值的位数需要扩展
reg			div_clk_r;
reg			clk2;

always @(posedge clk)begin
	if(rst)begin
		cnt <= 'd0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end

always @(posedge clk)begin
	if(rst)begin
		div_clk_r <= 1'b1;
	end
	else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1))begin
		div_clk_r <= 1'b0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1)begin
		div_clk_r <= 1'b1;
	end
end


always @(negedge clk)begin
	if(rst)begin
		clk2 <= 1'b1;
	end
	else if(cnt == ((DIVIDER_NUMBER - 1'b1) >> 1) && DIVIDER_NUMBER % 2 == 1'b1)begin
		clk2 <= 1'b0;
	end
	else if(cnt == DIVIDER_NUMBER - 1'b1 && DIVIDER_NUMBER % 2 == 1'b1)begin
		clk2 <= 1'b1;
	end
end

assign div_clk = ( DIVIDER_NUMBER % 2) ? div_clk_r && clk2 : div_clk_r;

endmodule

tb 文件如下:

// -----------------------------------------------------------------------------
// Copyright (c) 2014-2021 All rights reserved
// -----------------------------------------------------------------------------
// Author : dongtaolv
// Email  : tdlv@stu.xidian.edu.cn 
// File   : tb_random_divider.v
// Create : 2021-04-26 20:39:48
// Revise : 2021-04-26 20:39:48
// Editor : sublime text3, tab size (4)
// -----------------------------------------------------------------------------

`timescale 1ns/1ps

module tb_random_divider;

reg		clk;
reg		rst;
wire	div_clk;

initial begin
	clk = 0;
	rst = 1;
	#100
	rst = 0;
end

always #10 clk = ~clk;

random_divider #(
    .DIVIDER_NUMBER(7)      //通过设置此值来确定几分频
)
random_divider_inst(
	.clk		(clk	),
	.rst		(rst	),
	.div_clk	(div_clk)
);

endmodule

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1253.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年7月25日 19:30
下一篇 2022年7月30日 21:18

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注