赞
踩
奇数分频器跟偶数分频器一样,当计数器的值等于分频系数(加1或者减1)的一半或等于分频系数时,时钟信号翻转。奇数分频器分频原理如下图:
上图的分频系数是3,用一个计数器在上升沿计数,每次计数到1翻转一次,每次计数到3再翻转一次,然后周期重复得到信号clkp1,它的周期就是clk的3倍,但是它的占空比不是50%(占空比就是clk为高的时间占整个时钟周期的百分比)。奇数分频想通过计数器直接分频出占空比是50%的时钟是不可能的,必须要通过中间的临时波形,做一些逻辑“与”“或”的动作才能得到占空比50%的分频时钟。
方法一作逻辑“与”操作
以下代码是个人的一个总结,实现了7分频,要想实现其他奇数分频,改变div数值即可(相比其他的,还是比较容易看懂理解的)。
module frequency_div #(parameter div = 6) ( input clk, input rst_n, output clk_div ); //奇数分频情况 reg [3:0]cnt; reg clk_test; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin cnt <= 4'b0; end else if(cnt == div) cnt <= 4'b0; else begin cnt <= cnt + 1; end end reg clk_1; always@(posedge clk or negedge rst_n)begin if(!rst_n)begin clk_1 <= 1'b0; end else if(cnt == div/2 +2)//注意个人写法,下文有分析 clk_1 <= 1'b0; else if(cnt == 4'd1) clk_1 <= 1'b1; end reg clk_2; always@(negedge clk or negedge rst_n)begin if(!rst_n)begin clk_2 <= 1'b0; end else if(cnt == div/2 +2) clk_2 <= 1'b0; else if(cnt == 4'd1) clk_2 <= 1'b1; end assign clk_div = clk_1 & clk_2; endmodule
代码中只需要定义clk_1和clk_2就行(注意上升沿触发和下降沿触发的区别),若要修改分频系数,改变div数值即可。
上述文中cnt == div/2 +2和cnt == 4’d1是对“奇数分频器跟偶数分频器一样,当计数器的值等于分频系数(加1或者减1)的一半或等于分频系数时,时钟信号翻转”的解释。至于为什么不选择cnt == div/2 +1和cnt == 4’d0,下文仿真会有解释。
先贴出tb文件代码:
`timescale 1ns / 1ps module tb_frequency_div( ); reg clk; reg rst_n; wire clk_div; initial begin clk = 1'b0; rst_n = 1'b0; #9 rst_n = 1'b1; end always #10 clk = ~clk; frequency_div u_frequency_div( .clk (clk), .rst_n (rst_n), .clk_div (clk_div) ); endmodule
选择cnt == div/2 +1和cnt == 4’d0的仿真:
选择cnt == div/2 +2和cnt == 4’d1的仿真:
可以发现复位之后,第一种有一段缺失,效果较差,第二种更完整一些,故选择第二种。这边对于这段代码做出解释,防止阅读难以理解。
方法二做逻辑“或”操作
相比逻辑与操作更加容易理解与实现一些
实现5分频代码:
module fre_div ( input clk, input rst_n, output clk_div ); reg clk_div1; reg clk_div2; reg [2:0]cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 3'd0; end else if(cnt != 3'd4)begin cnt <= cnt + 1'b1; end else begin cnt <= 3'd0; end end always @(posedge clk or negedge rst_n) begin if (!rst_n) begin clk_div1 <= 1'b0; end else if (cnt == 3'd0) begin clk_div1 <= ~clk_div1; end else if (cnt == 3'd2) begin clk_div1 <= ~clk_div1; end else begin clk_div1 <= clk_div1; end end always @(negedge clk or negedge rst_n) begin if (!rst_n) begin clk_div2 <= 1'b0; end else begin clk_div2 <= clk_div1; end end assign clk_div = clk_div1 | clk_div2; endmodule
tb文件
`timescale 1ns/100ps module tb_fre_div (); reg clk; reg rst_n; wire clk_div; initial begin clk = 0; rst_n = 0; #10 rst_n = 1; end always #10 clk = ~clk; fre_div u_fre_div( .clk (clk), .rst_n (rst_n), .clk_div (clk_div) ); endmodule
仿真结果
可以观察到逻辑或的规律是:计数cnt计到想要分频的n-1次(从0开始),clk_div1在cnt为0时候翻转一次,然后在(n-1)/2的时候再翻转一次,然后clk_div2在下降沿采样clk_div1,最后将两个信号取或操作即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。