VL41. 任意小数分频
描述
请设计一个可以实现任意小数分频的时钟分频器,比如说8.7分频的时钟信号
注意rst为低电平复位
提示:
其实本质上是一个简单的数学问题,即如何使用最小公倍数得到时钟周期的分别频比。
设小数为nn,此处以8.7倍分频的时钟周期为例。
首先,由于不能在硬件上进行小数的运算(比如2.1个时钟这种是不现实的,也不存在3.3个寄存器),小数分频不能做到分频后每个时钟周期都是源时钟的nn倍,也无法实现占空比为1/2,因此,考虑小数分频,其实现方式应当为53个clkout时钟周期是10个clkin时钟周期的8.7倍。
信号示意图:
输入描述
输出描述
输出信号 clk_outVerilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`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***********// reg [6:0] cnt; reg [3:0] cnt1, cnt2; reg clk_MN; assign clk_out = clk_MN; always @(posedge clk_in, negedge rst) begin if(!rst) cnt <= 7'd0; else begin if(cnt == M_N-1) cnt <= 7'd0; else cnt <= cnt+1; end end always @(posedge clk_in or negedge rst) begin if(!rst) begin cnt1 <= 4'b0; cnt2 <= 4'b0; end else if(cnt<=c89-1'b1) begin cnt2 <= 4'd0; if(cnt1 == div_e - 1'b1) cnt1 <= 4'd0; else cnt1 <= cnt1 + 1'b1; end else if(cnt>c89-1'b1) begin cnt1 <= 4'd0; if(cnt2 == div_o - 1'b1) cnt2 <= 4'd0; else cnt2 <= cnt2 + 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(cnt1 == 4'd0 || cnt1 == div_e/2) clk_MN <= ~clk_MN; end if(cnt>=c89) begin if(cnt2 == 4'd0 || cnt2 == (div_o - 1'b1)/2) clk_MN <= ~clk_MN; end end end //*************code***********// endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`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***********// reg [3:0] clk_cnt; reg [6:0] cyc_cnt; reg div_flag; reg clk_out_r; always@(posedge clk_in or negedge rst) begin if(~rst) clk_cnt <= 0; else if (~div_flag) clk_cnt <= (clk_cnt==(div_e-1))?0:clk_cnt+1; else clk_cnt <= (clk_cnt==(div_o-1))?0:clk_cnt+1; end always@(posedge clk_in or negedge rst) begin if(~rst) cyc_cnt <= 0; else cyc_cnt <= (cyc_cnt==(M_N-1))?0:cyc_cnt+1; end always@(posedge clk_in or negedge rst) begin if(~rst) div_flag <= 0; else div_flag <= (cyc_cnt==(M_N-1)||cyc_cnt==(c89-1))?~div_flag:div_flag; end always@(posedge clk_in or negedge rst)begin if(~rst) clk_out_r <= 0; else if (~div_flag) clk_out_r <= clk_cnt<=((div_e>>2)+1); else clk_out_r <= clk_cnt<=((div_o>>2)+1); end assign clk_out = clk_out_r; //*************code***********// endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`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***********// reg [7:0] cyc_cnt; //对clk_in进行计数,达到M_N后清零。 reg div_flag; //8/9分频标志。当div_flag==0时是8分频;当div_flag==1时是9分频。 reg [3:0] clk_cnt; //用于产生分频输出。当div_flag==0时,计数最大值是div_e-1;当div_flag==1时,计数最大值是div_o-1。 reg clk_out_r; //根据clk_cnt和div_flag产生分频输出。 always@(posedge clk_in,negedge rst)begin if(~rst) clk_cnt <= 4'd0; else if(~div_flag) clk_cnt <= clk_cnt==(div_e-1)? 0:clk_cnt+1; else clk_cnt <= clk_cnt==(div_o-1)? 0:clk_cnt+1; end always@(posedge clk_in,negedge rst)begin if(~rst) cyc_cnt <= 8'd0; else cyc_cnt <= cyc_cnt==(M_N-1)? 0:cyc_cnt+1; end always@(posedge clk_in, negedge rst)begin if(~rst) div_flag <= 1'b0; else div_flag <= cyc_cnt==(M_N-1)||cyc_cnt==(c89-1)? ~div_flag:div_flag; end always@(posedge clk_cnt, negedge rst)begin if(~rst) clk_out_r <= 1'b0; else begin if(div_flag==0) clk_out_r <= clk_cnt<=((div_e>>2)+1); else clk_out_r <= clk_cnt<=((div_o>>2)+1); end end assign clk_out = clk_out_r; //*************code***********// endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`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***********// reg [7:0] cnt; reg div_flag; //0 进行8分频 1 进行9分频 reg [4:0] cnt_e; //对偶数分频进行计数 reg [4:0] cnt_o; //对奇数分频进行计数 reg clk_out_r; always @(posedge clk_in or negedge rst) begin if (rst == 1'b0) begin cnt <= 'd0; end else begin cnt <= (cnt == (M_N-1)) ? 'd0 : (cnt + 1'b1); end end always @(posedge clk_in or negedge rst) begin if (rst == 1'b0) begin div_flag <= 1'b0; end else if (cnt == (M_N-1)) begin div_flag <= 1'b0; end else if (cnt == (c89-1)) begin div_flag <= 1'b1; end end always @(posedge clk_in or negedge rst) begin if (rst == 1'b0) begin cnt_e <= 'd0; end else begin cnt_e <= (div_flag == 1'b1) ? 'd0 : (cnt_e == (div_e-1)) ? 'd0 : (cnt_e+1); end end always @(posedge clk_in or negedge rst) begin if (rst == 1'b0) begin cnt_o <= 'd0; end else begin cnt_o <= (div_flag == 1'b0) ? 'd0 : (cnt_o == (div_o-1)) ? 'd0 : (cnt_o+1); end end always @(posedge clk_in or negedge rst) begin if (rst == 0) begin clk_out_r <= 1'b0; end else if (div_flag == 0) begin clk_out_r <= (cnt_e <= ( (div_e>>2) + 1 ) ); // 小于一半计数值的时候就为1,否则为0 end else if (div_flag == 1) begin clk_out_r <= (cnt_o <= ( (div_o>>2) + 1 ) ); // 小于一半计数值的时候就为1,否则为0 end end assign clk_out = clk_out_r; //*************code***********// endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`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; always@(posedge clk_in or negedge rst) begin if(~rst) cnt<=7'd0; else begin if(cnt==86) cnt<=0; else cnt<=cnt+1; end end reg[2:0]cnt_8; reg[3:0]cnt_9; always@(posedge clk_in or negedge rst) begin if(~rst) begin cnt_8<=0; cnt_9<=0; end else begin if(cnt<c89) cnt_8<=cnt_8+1; else begin if(cnt_9==div_o-1) cnt_9<=0; else cnt_9<=cnt_9+1; end end end reg clk_r; always@(posedge clk_in or negedge rst) begin if(~rst) clk_r<=0; else begin if(cnt<c89) begin if(cnt_8<4) clk_r<=1; else clk_r<=0; end else begin if(cnt_9<4) clk_r<=1; else clk_r<=0; end end end assign clk_out=clk_r; endmodule