任意奇数分频

Posted by SkyCity's Blog on November 17, 2019

对时钟信号进行任意奇数分频,并仿真实现分频信号。

—————————————————————————————————————

1 三分频

1.1 三分频时序

首先来讲三分频电路逻辑,如何实现占空比为50%的三分频,也是硬件逻辑笔试题中常提的问题。其实三分频电路有很多种方法,这里选用其中一种:

先对时钟信号进行上升沿和下降沿触发的两个模三计数,当计数器计数到0和1时进行两次翻转,从而求出两个占空比为1/3的频率波形,分别为上升沿触发和下降沿触发,再将两个信号波形进行或运算。时序图如下:

Aaron Swartz

1.2 三分频代码

对上升沿和下降沿分别进行模三计数

1
2
3
4
5
6
7
8
9
reg	[15:0]	cnt_pos;    //上升沿计数
always@(posedge clk_in or negedge rst_n) begin
	if(!rst_n)
		cnt_pos <= 1'b0;
	else if(cnt_pos == 0)
		cnt_pos <= 1'b0;
	else
		cnt_pos <= cnt_pos + 1'b1;
end
1
2
3
4
5
6
7
8
9
reg	[15:0]	cnt_neg;    //下降沿计数
always@(negedge clk_in or negedge rst_n) begin
	if(!rst_n)
		cnt_neg <= 1'b0;
	else if(cnt_neg == (DIV - 1'b1))
		cnt_neg <= 1'b0;
	else
		cnt_neg <= cnt_neg + 1'b1;
end

当计数器计数到0和1时进行两次翻转

1
2
3
4
5
6
7
8
9
10
11
reg	clk_pos;    //  上升沿触发时钟
always@(posedge clk_in or negedge rst_n) begin
	if(!rst_n)
		clk_pos <= 1'b1;
	else if(cnt_pos == 0)
		clk_pos <= 1'b0;
	else if(cnt_pos == 1'b0)
		clk_pos <= 1'b1;
	else
		clk_pos <= clk_pos;
end
1
2
3
4
5
6
7
8
9
10
11
reg	clk_neg;
always@(negedge clk_in or negedge rst_n) begin
	if(!rst_n)
		clk_neg <= 1'b1;
	else if(cnt_neg == ((DIV - 1'b1)/2))
		clk_neg <= 1'b0;
	else if(cnt_neg == 1'b0)
		clk_neg <= 1'b1;
	else
		clk_neg <= clk_neg;
end

将两个信号波形进行或运算

1
assign	clk_out = clk_pos | clk_neg;

1.3 三分频仿真实现

用modelsim对逻辑代码进行仿真,得到的仿真图如下:

Aaron Swartz

2 任意奇数分频

2.1 任意奇数分频逻辑

任意奇数分频只要在三分频的基础上进行修改即可,比如进行N分频,就让计数器进行模N计数,然后在计数到0和(N-1)/2的时候翻转,其余不变。

2.2 任意奇数分频代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module	divide_N
#(parameter DIV = 7)
(		input		clk_in,
		input		rst_n,
		output	clk_out
);

reg	clk_pos;
reg	clk_neg;

reg	[15:0]	cnt_pos;
reg	[15:0]	cnt_neg;

always@(posedge clk_in or negedge rst_n) begin
	if(!rst_n)
		cnt_pos <= 1'b0;
	else if(cnt_pos == (DIV - 1'b1))
		cnt_pos <= 1'b0;
	else
		cnt_pos <= cnt_pos + 1'b1;
end

always@(posedge clk_in or negedge rst_n) begin
	if(!rst_n)
		clk_pos <= 1'b1;
	else if(cnt_pos == ((DIV - 1'b1)/2))
		clk_pos <= 1'b0;
	else if(cnt_pos == 1'b0)
		clk_pos <= 1'b1;
	else
		clk_pos <= clk_pos;
end

always@(negedge clk_in or negedge rst_n) begin
	if(!rst_n)
		cnt_neg <= 1'b0;
	else if(cnt_neg == (DIV - 1'b1))
		cnt_neg <= 1'b0;
	else
		cnt_neg <= cnt_neg + 1'b1;
end

always@(negedge clk_in or negedge rst_n) begin
	if(!rst_n)
		clk_neg <= 1'b1;
	else if(cnt_neg == ((DIV - 1'b1)/2))
		clk_neg <= 1'b0;
	else if(cnt_neg == 1'b0)
		clk_neg <= 1'b1;
	else
		clk_neg <= clk_neg;
end

assign	clk_out = clk_pos | clk_neg;

endmodule

2.3 任意奇数分频测试模块代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
`timescale 1ns/1ns
`define CLK50M_PERIOD 20

module	divide_N_tb;
	reg	clk;
	reg	rst_n;
	wire	clk_out;
	
parameter	DIV = 7;
initial clk = 1'b1;
always #(`CLK50M_PERIOD/2) clk = ~clk;

initial begin
	rst_n = 0;
	#(`CLK50M_PERIOD * 20 + 1)
	rst_n = 1;
	
	#5000;
	$stop;
end

divide_N
#(	.DIV(DIV)
	)divide_N
(	.clk_in(clk),
	.rst_n(rst_n),
	.clk_out(clk_out)
);

endmodule

2.4 任意奇数分频仿真实现

以7分频为例:

Aaron Swartz

—————————————————————————————————————

HOME