任意小数分频
题目描述
请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号
注意rst为低电平复位
提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
信号示意图:
题目解读
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为87个clkout时钟周期是10个clkin时钟周期的8.7倍。
所以很简单,根据提示,我们可以进行如下假设:首先设置有两个整数分频电路,一个是奇数一个是偶数,设其分频比为a和b,然后其分别的时钟占N/M个周期。则我们可以得到:
aN+bM = 87
N+M = 10
如果使用 8 和 9分频,则有:
8N+9M = 87
N+M = 10
因此 M为7, N为3。
具体步骤:
1)设计一个计数次数87的计数器,即0-86
2)分别生成8分频和9分频的计数器,计数次数分别为0-6和0-2
3)输出波形根据总计数器和8、9分频计数器的数值控制输出脉冲翻转
`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; //奇数周期
reg [6:0] cnt;
reg [3:0] cnt_e;
reg [3:0] cnt_o;
reg clk_MN;
assign clk_out = clk_MN;
//总计数器
always @(posedge clk_in or negedge rst) begin
if(!rst)
cnt <= 6'b0;
else begin
if(cnt == M_N - 1'b1)
cnt <= 6'b0;
else
cnt <= cnt + 1'b1;
end
end
always @(posedge clk_in or negedge rst) begin
if(!rst) begin
cnt_e <= 4'b0;
cnt_o <= 4'b0;
end
else if(cnt<=c89-1'b1) begin
cnt_o <= 4'd0;
if(cnt_e == div_e - 1'b1)
cnt_e <= 4'd0;
else
cnt_e <= cnt_e + 1'b1;
end
else if(cnt>c89-1'b1) begin
cnt_e <= 4'd0;
if(cnt_o == div_o - 1'b1)
cnt_o <= 4'd0;
else
cnt_o <= cnt_o + 1'b1;
end
end
always @(posedge clk_in or negedge rst) begin
if(!rst)
clk_MN <= 1'b0;
else begin
if(cnt<c89) begin
if(cnt_e == 4'd0 || cnt_e == div_e/2)
clk_MN <= ~clk_MN;
end
if(cnt>=c89) begin
if(cnt_o == 4'd0 || cnt_o == (div_o - 1'b1)/2)
clk_MN <= ~clk_MN;
end
end
end
endmodule