题目描述
请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号
注意rst为低电平复位
提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
题目解析:
8.7倍分频,即周期变为原来的8.7倍,周期计数不存在0.几个周期,所以需要将87个clk,转换为输出的10个周期,这就实现了8.7倍分频。类似的,小数倍都可以用这种方法。
进一步的,为了使得周期更加接近,且尽量靠近50%的占空比,在这一题里用了拆分输出周期长度的方法,分别以离8.7最近的两个整数8和9,以8个clk和9个clk为周期进行拆分。
所以,由于需要满足总周期为10,且和为87,则有,易得,8clk为周期的有三个,9clk为周期的有7个。可以得出他们分别的计数周期为8和9.
而对于偶数周期8,4clk跳变一次,对于奇数周期9, 4clk和5clk跳变一次。
此方法针对所有的小数都适用,总结流程为:
1、确定周期数之比;如8.7——87比10, 4.2——21比5。
2、确定奇数和偶数周期的长度;如8.7——87比10——8和9;4.2——21比5——2和3。
3、计算奇数和偶数周期个数;如8.7—87比10—8和9—3个/7个;4.2—21比5—4和5—4个/1个。
4、分别设置一个奇数偶数的计数器,偶数周期num/2时跳变,奇数周期(num-1/2)时跳变。
注意:若奇数周期也一定要求50%的占空比,则可以结合原输入clk的所有边沿进行考虑。
具体代码详解如下:
`timescale 1ns/1ns
module div_M_N(
input wire clk_in,
input wire rst,
output wire clk_out
);
parameter M_N = 8'd87;
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期
//*************code***********//
//需要一个clk_in的计数器 cnt1,计数87个clk周期
reg [6:0] cnt1;
always @(posedge clk_in or negedge rst) begin
if(!rst)
cnt1 <= 0 ;
else
cnt1 <=(cnt1==M_N-1)? 0 : cnt1 + 1;
end
//需要对奇数周期和偶数周期进行计数 cnt_e cnt_o
reg [3:0] cnt_e,cnt_o; //位宽一开始写成3bits了,要注意3bits只能计到7
always @(posedge clk_in or negedge rst) begin
if(!rst) begin
cnt_e <= 0;
cnt_o <= 0;
end
else if(cnt1 <= c89-1)
cnt_e <= ( cnt_e == div_e-1 )? 0 : cnt_e +1; //偶数周期
else if(cnt1 > c89-1)
cnt_o <= ( cnt_o == div_o-1 )? 0 : cnt_o + 1; //奇数周期
end
//输出out1
reg out;
always @(posedge clk_in or negedge rst) begin
if(!rst)
out <= 0 ;
else if( ((cnt_e == 4 | cnt_e == 0)&&(cnt1 <c89 )) | ( (cnt_o == 0 | cnt_o == 4)&&(cnt1 >= c89 )) )
//条件判断,偶数周期,4clk翻转一次;期数周期,在4clk和5clk翻转
out <= ~out ;
end
assign clk_out = out;
//*************code***********//
endmodule
结束啦!