题解 | #任意小数分频#
任意小数分频
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; //奇数周期 // ================================================================================================== // 关于Verilog编写小数分频电路,最开始确实没有头绪。牛客上本题的解析还是很到位的,第一个题解教会了我如何思考, // 第二个题解教会了我这题如何编码: //1 https://blog.nowcoder.net/n/a4d81838e9d24ceca35797c4754b7fe8 //2 https://blog.nowcoder.net/n/7d57a3086a6448f69637cf284b492f3b // Verilog不可能精确地实现小数的分频,只能通过多个周期,以及不同的整数分频数来模拟小数分频的效果。 // 这里需要实现8.7分频,即频率上 clk_in:clk_out=8.7:1=87:10,也就是说,8.7分频相当于87个clk_in内输出10个clk_out。 // 然后对于小数分频,采用小数的上下限整数来设置分频,因为8<8.7<9,所以8.7分频需要通过clk_in的8分频和9分频共同来模拟。 // 设10个clk_out周期中,有x个是clk_in的8分频时钟,有y个是clk_in的9分频时钟。 // 由方程 // x+y = 10 ① // 和 // 8x+9y = 87 ② // 解得: // x=3, y=7 // 即,对clk_in进行三次8分频和7次9分频,可以得到8.7分频的效果。 // 根据题目中已有的要求,c98=24=3×8 知,本题需要先进行8分频。 // ================================================================================================== //*************code***********// wire rst_n ; assign rst_n = rst ; reg [6:0] cnt_total; always @(posedge clk_in or negedge rst_n) begin if(~rst_n) cnt_total <= 'd0; else cnt_total <= (cnt_total==M_N-1'd1)? 'd0 : cnt_total+1'd1; end reg [3:0] cnt_div_8; // 8分频的计数器 reg [3:0] cnt_div_9; // 9分频的计数器 // 8,9分频的计数器逻辑 always @(posedge clk_in or negedge rst_n) begin if(~rst_n) begin cnt_div_8 <= 'd0; cnt_div_9 <= 'd0; end else begin if(cnt_total <= c89-1) begin cnt_div_8 <= (cnt_div_8==DIV_E-1)? 'd0 : cnt_div_8+1'd1; cnt_div_9 <= 'd0; end else if(cnt_total > c89-1) begin cnt_div_9 <= (cnt_div_9==DIV_O-1)? 'd0 : cnt_div_9+1'd1; cnt_div_8 <= 'd0; end else begin cnt_div_8 <= 'd0; cnt_div_9 <= 'd0; end end end reg clk_out_r; assign clk_out = clk_out_r; // 输出逻辑 always @(posedge clk_in or negedge rst_n) begin if(~rst_n) clk_out_r <= 1'b0; else begin if(cnt_total <= c89-1) // 执行 8 分频输出 clk_out_r <= (cnt_div_8==((DIV_E>>1)) || cnt_div_8=='d0)? ~clk_out_r : clk_out_r; else if(cnt_total > c89-1) // 执行 9 分频输出 clk_out_r <= (cnt_div_9==((DIV_O>>1)) || cnt_div_9=='d0)? ~clk_out_r : clk_out_r; else clk_out_r <= clk_out_r; end end //*************code***********// endmodule