1. 偶数分频器
// 偶数分频器示例,20分频即N=10,占空比50%
module Fre_div_even(
input clk,
input rst_n,
input [3:0] N, // N = 分频倍数/2
output reg clk_out
);
reg [3:0] cnt;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= 4'b0;
clk_out <= 1'b0;
end
else
begin
if(cnt == N-1)
begin
clk_out <= ~clk_out;
cnt <= 4'b0;
end
else
begin
cnt <= cnt + 4'b1;
end
end
end
endmodule
2. 奇数分频器
- 奇数分频相对于偶数分频较为复杂,尤其是占空比为50%的奇数分频,可以采用错位相和的方法,即分别用上升沿和下降沿产生2:3占空比的N分频时钟,并将输出进行或运算得到
// 奇数分频器示例,5分频即N=5,占空比50%
module Fre_div_odd(
input clk,
input rst_n,
input [3:0] N, // N分频
output clk_out
);
reg clk_n;
reg clk_p;
reg [3:0] cnt_p;
reg [3:0] cnt_n;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_p <= 1'b0;
cnt_p <= 4'b0;
end
else
begin
if(cnt_p == N-1)
begin
clk_p <= ~clk_p;
cnt_p <= 4'b0;
end
else if(cnt_p == (N-1)/2)
begin
clk_p <= ~clk_p;
cnt_p <= cnt_p + 1;
end
else
begin
cnt_p <= cnt_p + 1;
clk_p <= clk_p;
end
end
end
always @(negedge clk or negedge rst_n)
begin
if(!rst_n)
begin
clk_n <= 1'b0;
cnt_n <= 4'b0;
end
else
begin
if(cnt_n == N-1)
begin
clk_n <= ~clk_n;
cnt_n <= 4'b0;
end
else if(cnt_n == (N-1)/2)
begin
clk_n <= ~clk_n;
cnt_n <= cnt_n + 1;
end
else
begin
cnt_n <= cnt_n + 1;
clk_p <= clk_p;
end
end
end
assign clk_out = clk_n | clk_p;
endmodule
3.半分频器
- 在实际工程中,经常遇到需要半分频的情况,例如时钟晶振为25MHz,而我们需要用到2MHz的时钟信号,就需要进行12.5分频。
- 半分频无法实现50%占空比,因为实现需要得到时钟信号的0.25周期,是无法实现的,因此只能使占空比尽量接近50%。
- 半分频可以在奇数分频器额基础上实现,利用已经得到的奇数分频时钟信号将原时钟信号的后半段翻转;然后再对翻转后的波形计数,得到的波形与奇数分频得到的波形进行异或后即可得到需要的半分频时钟信号
- 波形图如下:

// 半分频器示例,以2.5分频为例,即N=2
module Fre_div_half(
input clk,
input rst_n,
input [3:0] N, // 即实现N+0.5分频
output clk_out
);
wire clk_div_odd;
wire clk_rev;
/* 按照上文的实现方法搭建奇数分频
N_odd = 2 * N + 1
具体实现省略
奇数分频后得到clk_div_odd */
Fre_div_odd Fre_div_odd(
.clk(clk),
.rst_n(rst_n),
.N(2*N+1),
.clk_out(clk_div_odd)
);
assign clk_rev = clk_div_odd ? ~clk : clk;
reg [3:0] cnt_rev;
reg clk_rev_div;
always @(posedge clk_rev or negedge rst_n)
begin
if(!rst_n)
begin
clk_rev_div <= 0;
cnt_rev <= 0;
end
else
begin
if(cnt_rev == N/2)
begin
clk_rev_div <= ~clk_rev_div;
cnt_rev <= cnt_rev + 1;
end
else if(cnt_rev == N)
begin
cnt_rev <= 0;
end
else
begin
cnt_rev <= cnt_rev + 1;
clk_rev_div <= clk_rev_div;
end
end
end
assign clk_out = clk_div_odd ^ clk_rev_div;
endmodule
仿真
- 将三个分频器加入同一工程,并进行仿真
- 顶层模块和testbunch代码如下
// 顶层模块,调用三种分频器模块
module Fre_div(
input clk,
input rst_n,
output clk_out_even,
output clk_out_odd,
output clk_out_half
);
parameter N_even = 4;
parameter N_odd = 5;
parameter N_half = 3;
Fre_div_even Fre_div_even(
.clk(clk),
.rst_n(rst_n),
.N(N_even),
.clk_out(clk_out_even)
);
Fre_div_odd Fre_div_odd(
.clk(clk),
.rst_n(rst_n),
.N(N_odd),
.clk_out(clk_out_odd)
);
Fre_div_half Fre_div_half(
.clk(clk),
.rst_n(rst_n),
.N(N_half),
.clk_out(clk_out_half)
);
endmodule
// 测试模块
module Fre_div_test;
// Inputs
reg clk;
reg rst_n;
// Outputs
wire clk_out_even;
wire clk_out_odd;
wire clk_out_half;
// Instantiate the Unit Under Test (UUT)
Fre_div uut (
.clk(clk),
.rst_n(rst_n),
.clk_out_even(clk_out_even),
.clk_out_odd(clk_out_odd),
.clk_out_half(clk_out_half)
);
initial begin
// Initialize Inputs
clk = 1;
rst_n = 1;
// Wait 100 ns for global reset to finish
#50;
rst_n = 0;
#50;
rst_n = 1;
forever #50 clk = ~clk;
// Add stimulus here
end
endmodule
- 仿真结果如下: