1.偶数分频
对于占空比为50%,分频系数为N的偶数分频,其核心思想是使用计数范围为[0, (N/2)-1]的计数器,每当计数器计到最大值时输出时钟翻转一次,其余时间保持不变。
八分频示意图
2.奇数分频
奇数分频比偶数稍微复杂一些,为了实现50%的占空比,需要分别设置上升沿和下降沿触发的计数器,其核心思想是使用计数范围为[0, (N-1)/2]和[0, (N-1)]的计数器,各自输出当前有效沿下的时钟,最后将二者或起来,得到最终输出的时钟信号。
五分频示意图
3.代码文件说明
分频器的代码并不难,网上多数是奇偶分频分开写的代码,按照电路结构去理解,分频器分为奇偶数两个module是比较理想的。如果把奇偶两个模块写到一个module中,则会导致输出经过较多的逻辑电路,而且每次调用都会用上奇偶分频的全部模块,会浪费很多资源。调用本次代码时,只需例化Div.v,本次代码得到的都是 占空比为50% 的时钟。
名字 | 说明 |
---|---|
div_even.v | 偶数分频module |
div_odd.v | 奇数分频module |
Div.v | 例化奇偶分频module的顶层 |
4.端口说明
仅以Div.v这个module来说明:
名字 | 类型 | 说明 |
---|---|---|
fre_div | parameter | 分频数 |
clk | input | 输入时钟 |
rst_n | input | 复位 |
clk_out | output | 输出时钟 |
5.测试&波形
为了进行测试,写了一个TOP文件:
//-----------------------------------------------------------------------------------------------
// Copyright :
// File Name : TOP
// Author : Luk.wj
// Data : 2021.10.14
// Description : TOP file for test
//-----------------------------------------------------------------------------------------------
module TOP #(
parameter fre_div = 4 //frequency division
) (
input clk,
input rst_n,
output clk_out
);
Div#(
.fre_div ( fre_div )
)u1_Div(
.clk ( clk ),
.rst_n ( rst_n ),
.clk_out ( clk_out )
);
endmodule
测试中是四分频,波形如下图:
如果需要其他分频数,只需修改传递的参数即可。
6.代码
div_even.v代码:
//-----------------------------------------------------------------------------------------------
// Copyright :
// File Name : div_even
// Author : Luk.wj
// Data : 2021.10.13
// Description : Even frequency division
//-----------------------------------------------------------------------------------------------
module div_even #(
parameter fre_div = 4 //frequency division
) (
input clk,
input rst_n,
output reg clk_out
);
reg [fre_div/2-1:0] cnt;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 0;
clk_out <= 1'b0;
end
else if (cnt == (fre_div/2-1)) begin
cnt <= 0;
clk_out <= ~clk_out;
end
else
cnt <= cnt + 1;
end
endmodule
div_odd.v代码:
//-----------------------------------------------------------------------------------------------
// Copyright :
// File Name : div_odd
// Author : Luk.wj
// Data : 2021.10.13
// Description : Odd numkber frequency division
//-----------------------------------------------------------------------------------------------
module div_odd #(
parameter fre_div = 5 //frequency division
) (
input clk,
input rst_n,
output clk_out
);
reg [(fre_div-1)/2:0] cnt_p, cnt_n; //posedge, negedge count
reg clk_p, clk_n; //posedge, negedge generate clock
//==================================================== clk_p unit
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_p <= 0;
clk_p <= 1'b0;
end
else if (cnt_p == (fre_div-1)/2) begin
clk_p <= ~clk_p;
cnt_p <= cnt_p + 1;
end
else if (cnt_p == (fre_div-1)) begin
cnt_p <= 0;
clk_p <= ~clk_p;
end
else
cnt_p <= cnt_p + 1;
end
//==================================================== clk_n unit
always @(negedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt_n <= 0;
clk_n <= 1'b0;
end
else if (cnt_n == (fre_div-1)/2) begin
clk_n <= ~clk_n;
cnt_n <= cnt_n + 1;
end
else if (cnt_n == (fre_div-1)) begin
cnt_n <= 0;
clk_n <= ~clk_n;
end
else
cnt_n <= cnt_n + 1;
end
assign clk_out = clk_p | clk_n;
endmodule
Div.v代码:
//-----------------------------------------------------------------------------------------------
// Copyright :
// File Name : Div
// Author : Luk.wj
// Data : 2021.10.14
// Description : Any integer frequency division module
//-----------------------------------------------------------------------------------------------
module Div #(
parameter fre_div = 4 //frequency division
) (
input rst_n,
input clk,
output clk_out
);
generate
// Even
if (fre_div[0] == 1'b0) begin: div
div_even#(
.fre_div ( fre_div )
) u1_div_even(
.clk ( clk ),
.rst_n ( rst_n ),
.clk_out ( clk_out )
);
end
// Odd
else begin: div
div_odd#(
.fre_div ( fre_div )
) u1_div_odd(
.clk ( clk ),
.rst_n ( rst_n ),
.clk_out ( clk_out )
);
end
endgenerate
endmodule
7.Reference
https://blog.youkuaiyun.com/qq_36550892/article/details/126278909