小数分频器实现–以8.7分频为例

  • Post author:
  • Post category:其他




1.如何进行小数分频

一般情况下我们会用到三种分频:偶数分频、奇数分频和小数分频。偶数分频最容易实现,且肯定能保证百分之五十占空比;奇数分频比较容易实现,如果追求百分之五十占空比的话,会麻烦一些;小数分频相对来说比较麻烦,本文主要结合8.7分频讲解小数分频实现原理。

由于时钟是不可分的,所以我们不可能像普通分频那样,8.7个输入时钟对应一个输出时钟,于是我们转换思路,用87个输入时钟对应10个输出时钟。同样由于时钟不可分,我们需要使用两个不同的分频时钟进行拼接,凑齐87个时钟,所以模块的输出时钟必然不可能是均匀的。

由于





8

<

8.7

<

9

8 < 8.7<9






8




<








8.7




<








9







所以我们选择若干个8分频和9分频时钟拼接出10个输出时钟,使这10个输出时钟对应87个输入时钟。那么在输出的10个时钟中,有多少个是8分频的,又有多少个是9分频的呢?设有x个8分频时钟,y个9分频时钟,那么





8

x

+

9

y

=

87

x

+

y

=

10

8x+9y=87\\ x+y=10






8


x




+








9


y




=








87








x




+








y




=








10





解得





x

=

3

y

=

7

x=3\\ y=7






x




=








3








y




=








7







所以有3个8分频时钟和7个9分频时钟。

所以最终我们得到这样一种效果:

在这里插入图片描述

同理,如果分频系数是别的小数,比如7.482,那么我们需要7分频时钟和8分频时钟进行组合,7482个输入时钟对应1000个输出时钟,可列方程组如下:





7

x

+

8

y

=

7482

x

+

y

=

1000

7x+8y=7482\\ x+y=1000






7


x




+








8


y




=








7482








x




+








y




=








1000







解之得:





x

=

518

y

=

482

x=518\\ y=482






x




=








518








y




=








482







也就是说需要512个7分频时钟和482个8分频时钟,对应输入的7482个时钟。



2.Verilog实现

上面对小数分频原理进行了解释,接下来以8.7分频为例对代码进行介绍。

首先我们必然需要一个计数器对输入时钟进行计数,计数范围为0-86共87个输入时钟。

parameter M_N = 8'd87; 
parameter c89 = 8'd24; // 8/9时钟切换点
parameter div_e = 5'd8; //偶数周期
parameter div_o = 5'd9; //奇数周期

reg[7:0]clk_count;
always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        clk_count <= 0;
    end
    else begin
        clk_count <= clk_count==M_N-1 ? 0 : clk_count+1; 
    end
end

同时对于输出的时钟,我们需要确定何时为高电平,何时为低电平,所以需要引入另一个计数器,对每个输出的时钟进行计数。比如此时是8分频时钟,计数范围0-7,计数器在0-3时,输出高电平,4-7时,输出低电平。当9分频时,0-3输出高电平,4-8输出低电平。

reg[7:0]cnt;
always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        cnt <= 0;
    end
    else if(div_class)begin
        cnt <= cnt==(div_e-1) ? 0 : cnt+1;
    end
    else begin
        cnt <= cnt==(div_o-1) ? 0 : cnt+1; 
    end
end

由于8分频时钟和9分频时钟,计数范围是不同的,一个0-7,一个0-8,所以我们引入一个变量,区分此时是8分频还是9分频。

wire div_class = clk_count < c89 ? 1 : 0;

最终就是模块的输出。右移一位是除以2的整数除法,无需多言。

reg clk_out_r;
always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        clk_out_r <= 0;
    end
    else if(div_class)begin
        clk_out_r <= (cnt < div_e>>1) ? 1 : 0;
    end
    else begin
        clk_out_r <= (cnt < div_o>>1) ? 1 : 0;
    end
end

assign clk_out = clk_out_r;

完整Verilog代码。

`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]clk_count;
reg[7:0]cnt;

always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        clk_count <= 0;
    end
    else begin
        clk_count <= clk_count==M_N-1 ? 0 : clk_count+1; 
    end
end

wire div_class = clk_count < c89 ? 1 : 0;

always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        cnt <= 0;
    end
    else if(div_class)begin
        cnt <= cnt==(div_e-1) ? 0 : cnt+1;
    end
    else begin
        cnt <= cnt==(div_o-1) ? 0 : cnt+1; 
    end
end

reg clk_out_r;
always @(posedge clk_in, negedge rst) begin
    if(rst == 0)begin
        clk_out_r <= 0;
    end
    else if(div_class)begin
        clk_out_r <= (cnt < div_e>>1) ? 1 : 0;
    end
    else begin
        clk_out_r <= (cnt < div_o>>1) ? 1 : 0;
    end
end

assign clk_out = clk_out_r;

//*************code***********//
endmodule



3.testbench及仿真结果

testbench较为简单。

`timescale 1ns/1ns

module div_M_N_tb(
 
);

reg clk_in;
reg rst;
wire clk_out;

initial begin
    clk_in <= 0;
    rst <= 0;

    #20 rst <= 1;
end

always begin
    #5 clk_in <= ~clk_in;
end

div_M_N dut(
    .clk_in(clk_in),
    .rst(rst),
    .clk_out(clk_out)
);

endmodule

仿真效果如图所示。

在这里插入图片描述



版权声明:本文为qq_37442263原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。