1.偶数分频器
假设N分频器,N是偶数,
第一种思路
(1)复位信号时,计数器清零,输出时钟置低电平
(2)计数器到 N/2 - 1 时,时钟翻转,计数器继续累加
(3)计数器到 N-1 时,时钟翻转,计数器清零
(4)计数器在其他值是输出保持,计数器继续累加
这种思路的思想是,在计数器为 0 ~N/2 -1 时,输出时钟保持一个状态 ,N/2~N-1时保持另一个状态。
比如8分频,1~4这四个原始T内,为低电平,此时计数器为0~3
5~8这四个原始T内,为高电平,此时计数器为4~7
至此,产生了一个8分频的输出时钟
第二种思路
(1)复位信号时,计数器清零,输出时钟置低电平
(2)计数器到 N/2 - 1 时,时钟翻转,计数器清零
(3)计数器为其余值时,继续保持加一
这种思路的思想是,在计数器为 0 ~N/2 -1 时,输出时钟保持一个状态 ,在计数器为下一个0 ~N/2 -1 时保持另一个状态。
比如8分频,1~4这四个原始T内,为低电平,此时计数器为0~3
5~8这四个原始T内,为高电平,此时计数器为0~3
2.奇数分频器
假设N分频器,N是奇数
(1)上升沿计数器 cnt_p,在0~(N-1)/ 2 之间 为一个电平,(N+1)/ 2到N-1之间为另一个电平,得到clk_p
(2)下降沿计数器 cnt_n,在0~(N-1)/ 2 之间 为一个电平,(N+1)/ 2到N-1之间为另一个电平,得到clk_n
(3)将两个时钟进行或运算即可得到clk_odd
rtl代码
module freq_div(
clk_in,
rst_n,
clk_out
);
localparam div_width = 3, //分频计数器位宽
fre_div = 7; //分频数
input wire clk_in ;
input wire rst_n ;
output wire clk_out ;
/* 偶数分频参数 */
reg clk_even;
reg [div_width-1:0] clk_even_cnt;
/* 奇数分频参数 */
reg clk_1,clk_2; //上升沿和下降沿时钟
wire clk_odd;
reg [div_width-1:0] clk_1_cnt , clk_2_cnt; //奇数计数器
assign clk_out = (fre_div == 1'b1)? clk_in : (fre_div[0]? clk_odd : clk_even); //输出
assign clk_odd = clk_1 | clk_2;
//偶数分频情况
always @ (posedge clk_in or negedge rst_n)
begin
if (!rst_n)
begin
clk_even <= 1'b0;
clk_even_cnt <= 3'd0;
end
else if (clk_even_cnt == fre_div/2-1)
begin
clk_even <= ~clk_even;
clk_even_cnt <= clk_even_cnt + 1'b1;
end
else if (clk_even_cnt == fre_div - 1)
begin
clk_even <= ~clk_even;
clk_even_cnt <= 3'd0;
end
else
begin
clk_even <= clk_even;
clk_even_cnt <= clk_even_cnt + 1'b1;
end
end
//奇数分频情况
always @ (posedge clk_in or negedge rst_n) //上升沿产生分频时钟
begin
if (!rst_n)
begin
clk_1 <= 1'b0;
clk_1_cnt <= 3'd0;
end
else if (clk_1_cnt == (fre_div-1)/2) //低电平时间比高电平时间多一个周期
begin
clk_1 <= ~clk_1;
clk_1_cnt <= clk_1_cnt + 1'b1;
end
else if (clk_1_cnt == fre_div - 1)
begin
clk_1 <= ~clk_1;
clk_1_cnt <= 3'd0;
end
else
begin
clk_1 <= clk_1;
clk_1_cnt <= clk_1_cnt + 1'b1;
end
end
always @ (negedge clk_in or negedge rst_n) //下降沿产生分频时钟
begin
if (!rst_n)
begin
clk_2 <= 1'b0;
clk_2_cnt <= 3'd0;
end
else if (clk_2_cnt == (fre_div-1)/2)
begin
clk_2 <= ~clk_2;
clk_2_cnt <= clk_2_cnt + 1'b1;
end
else if (clk_2_cnt == fre_div - 1)
begin
clk_2 <= ~clk_2;
clk_2_cnt <= 3'd0;
end
else
begin
clk_2 <= clk_2;
clk_2_cnt <= clk_2_cnt + 1'b1;
end
end
endmodule
testbench代码
`timescale 1ns/100ps
module tb();
reg clk_in ;
reg rst_n ;
wire clk_out ;
parameter DELAY = 18.5 ;
always #10 clk_in=~clk_in ;
initial
begin
rst_n=0;
clk_in=0;
#DELAY rst_n=1;
#300 $stop;
end
freq_div U_freq_div(.clk_in(clk_in),
.rst_n(rst_n),
.clk_out(clk_out)
);
endmodule
7分频仿真波形图
3.任意整数分频器
在有了奇偶分频器的基础上,只需要通过修改parameter中的 计数器位数与分频数N就可得到占空比为50%的任意整数分频器。
比如50Mhz时钟分频到880Khz,通过相除可以得到N为625,此时可以通过计算得到cnt计数器的位宽为10位,因此设计时只需要把div_width调成10,fre_div调成625,即可实现该分频。
4.占空比非50%整数分频器
上边的分频器都是基于50%占空比的整数分频器,如果要实现非均匀占空比,比如还是上边的50Mhz变成30%占空比的880Khz时钟。(占空比是指高电平在一个周期中持续的时间比例)
(1)计算625*30%=187.5
因此设计时,可以复位时输出时钟为低,计数器从0计数到187时,另输出电平为高,187~625时为低,计数到625计数器清零。继续下一个周期的计数。(如有错误请指正)
5.小数分频器
小数分频器,在阅读了一些csdn博客之后,我所理解的就是小数分频,比如19/9分频,是通过原始时钟的19*T_origin凑出输出时钟的9*T_out [1] 。分解成若干个奇分频和偶分频的组合
这里我找到一个二元一次方程
n*No+m*Ne=19
n+m=9
No为奇分频的N,Ne为偶分频的N
我们令No=3,Ne=2,则n=1,m=8 ;
理论上No和Ne的选择可以有多组解
至此19/9分频,就是用8个二分频和1个三分频去凑出9个周期。如图[1]
这里可以看到9个周期的时钟是先1个三分频然后8个二分频。
优点是算法简单。
缺点是占空比不是50%,因为2分频和3分频交叉组合而成,所以周期性抖动较差。
ACC计数器设计[2]
ACC计数器就是控制做N次ZN分频和M次ZN+1次分频,具体控制过程可以分为以下几种情况:
第1种情况 :先做N次ZN分频,再做M次ZN+1次分频;
第2种情况: 先做M次ZN+1次分频,再做N次ZN分频;
第3种情况 :把N次ZN分频平均插入到M次ZN+1分频中;
第4种情况 :把M次ZN+1次分频平均插入到N次ZN分频中。
组合N次ZN分频和M次ZN+1次分频的情况很多。第1、2种情况前后时钟频率不太均匀,因此相位抖动比较大;
第3、4种情况前后时钟频率均匀性稍好,因此相位抖动会减小
参考链接: