题解 | #任意小数分频#
任意小数分频
https://www.nowcoder.com/practice/24c56c17ebb0472caf2693d5d965eabb
`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只有整数,所以无法实现0.3个clk_in,所以小数分频不是精确的一个clk_out内输出8.3个clk_in,
//因为单个clk_in是最小的计数单位是整数,所以只能实现平均意义上的分频,比如本题8.7分频,
//那我们就在87个clk_in中输出10个clk_out,就相当于是8.7分频了,3*8+7*9=87,所以可以假设87个clk_in
//中3个8分频和7个9分频
reg flag;//标志是8分频还是9分频
reg clk_out_r;//因为题目clk_out给的是wire,所以定义一个reg转换一下
reg [6:0] cnt;//计数器,每87个时钟后清零
reg [3:0] cnt_div;//分频计数器,在8、9分频的一半时候跳转
//标志位,当计数器达到8,9分频器的交界翻转,即flag为0时是8分频器输出,1时是9分频器输出
//这里切记不要忘了cnt ==(M_N-1)时也要进行翻转
always @(posedge clk_in or negedge rst)begin
if(~rst)
flag <= 1'b0;
else
flag <= ((cnt==(c89-1))|(cnt ==(M_N-1)))?(~flag):flag;
end
//整个大周期计数器,从0到87-1共87个数
always @(posedge clk_in or negedge rst)begin
if(~rst)
cnt <= 1'b0;
else
cnt <= (cnt==(M_N-1))?0:cnt+1;
end
//这是分频器的计数器,8分频时计数器从0-7共8个数,9分频器从0-8共计9个数,
//这部分的作用是为了后面的clk_out翻转,clk_out要在分频器中间进行跳转
always @(posedge clk_in or negedge rst)begin
if(~rst)
cnt_div <= 4'b0;
else if(~flag)
cnt_div <= (cnt_div == (div_e-1))?1'b0:cnt_div+1;
else if(flag)
cnt_div <= (cnt_div == (div_o-1))?1'b0:cnt_div+1;
end
//这部分就是输出了,因为8分频器和9分频器中间都是4(9的分频器可以取4或者5),所以其实下面两个else的条件是一样的
//但是不知道为什么9分频器的条件改成cnt_div==5不行,按理来说可以,题目中的波形太小了懒得看,可能题目规定了
always @(posedge clk_in or negedge rst)begin
if(~rst)
clk_out_r <= 1'b0;
else if(~flag)
clk_out_r <= ((cnt_div==0)|(cnt_div==4))?(~clk_out_r):(clk_out_r);
else if(flag)
clk_out_r <= ((cnt_div==0)|(cnt_div==4))?(~clk_out_r):(clk_out_r);
end
assign clk_out = clk_out_r;
//*************code***********//
endmodule