任意奇偶分频器+任意小数分频

任意奇偶分频器

分频器是一种基本电路,是在所给信号频率的基础上,减少单位时间内脉冲个数的电路,根据分频的需求不同,将分频器分为偶数分频和奇数倍分频,非整数倍分频。整数倍频主要依赖于计数器来是实现,已输入的内部时钟信号为计数脉冲,按照计数次数规律地输出脉冲信号从而得到所要求的信号。
能够实现输入N的分频,其中偶分频的原理不同于奇分频,因为同时只有一个分频器有效,所以最终频率的输出为两者频率相或,其中主要框图如下:
在这里插入图片描述

偶分频的实现原理

对于任意的偶数分频,其输出已分频的信号的半周期一定是待分频信号周期的整数倍,也就是说已分频信号的跳变瞬间总是对应着原信号单一的跳变状态,因此,要实现偶数分频器,只要使用一个计数器对clk的跳变状态进行计数,便能控制输出信号的跳变。

当en有效,且N为偶数时,开始计数,在同一个分频后的时钟周期中计数二轮(N/2 - 1),当检测到N == 0时,偶分频信号翻转。

奇数分频的实现原理

对于任意的奇数倍分频,其输出已分频信号的半个周期一定是待分频信号周期的非整数倍,就是说已分频信号的跳变瞬间,并非对应原信号的单一跳变状态,因此需要使用两个计数器分别在上升沿和下降沿时触发计数,为实现按占空比50%分频,可选用于CLK相差1/2周期的两分频错位信号相“或”来实现。

刚开始我在计数分频时任然采用偶分频的方式,但是有错误,原理上采用上升沿和下降沿两种并行的计数,每个计数的原理都是相同的,各自触发时钟下以N为单位递减计数,当COUNT > (N+1)/2为高电平,否则为低电平,当count为0时,重新递减计数。

Verilog 实现

顶层模块div_clk.v

module div_clk(
    input           clk,
    input           rst_n,
    input   [7:0]   N,
    input           en,
    output          clk_out
    );

    wire  clk_out_e;
    wire  clk_out_o;



    assign clk_out  = clk_out_e | clk_out_o;

    dive_clk  inst_dive_clk(
        .clk(clk),
        .rst_n(rst_N),
        .en(en),
        .N(N),
        .clk_out_e(clk_out_e)
    );

    divo_clk  inst_divo_clk(
        .clk(clk),
        .rst_n(rst_N),
        .en(en),
        .N(N),
        .clk_out_o(clk_out_o)
    );


endmodule

偶数分频模块dive_clk.v

module dive_clk(
    input           clk,
    input           rst_n,
    input           en,
    input   [7:0]   N,
    output   reg    clk_out_e
    );

    reg  [7:0]   cnt;
    wire         E_enable;


    assign E_enable = ~N[0];

    always@(posedge clk)begin
        if(rst_n  == 0)begin
            cnt <= 8'b0;
            clk_out_e <= 1'b0;
        end
        else begin
            if(en & ~N[0])  begin    //偶分频
                if(cnt == 8'b0)begin
                    clk_out_e <= ~clk_out_e;
                    cnt <= N/2 -1;
                end
                else begin
                    clk_out_e <= clk_out_e;
                    cnt <= cnt - 1'b1;
                end
            end
            else begin             //是奇分频,或者没有使能
                clk_out_e <= 1'b0;
                cnt <= 8'b0;
            end
        end
    end


endmodule

奇数分频器模块divo_clk.v


module divo_clk(
    input           clk,
    input           rst_n,
    input   [7:0]   N,
    input           en,
    output          clk_out_o
    );

   
    reg  [7:0]   cnt_a,cnt_b;
    reg  clk_a,clk_b;

    wire O_enable ;
    assign O_enable = N[0];
    assign clk_out_o = clk_a | clk_b;


    always@(posedge clk)begin
        if(rst_n  == 0)begin
            cnt_a <= 8'b0;
            clk_a <= 1'b0;
        end
        else begin 
            if(en & N[0]) begin    //奇数分频
                if(cnt_a == 8'b0) begin
                    cnt_a <= N -1;
                    clk_a <= 1'b1;
                end
                else if(cnt_a > ((N + 1) /2)) begin
                    cnt_a <= cnt_a - 1'b1;
                    clk_a <= 1'b1;
                end
                else begin
                    cnt_a <= cnt_a - 1'b1;
                    clk_a <= 1'b0;
                end
            end
            else begin
                clk_a <= 1'b0;
                cnt_a <= 8'b0;
            end
        end
    end



    always@(negedge clk)begin
        if(rst_n  == 0 )begin
            cnt_b <= 8'b0;
            clk_b <= 1'b0;
        end
        else begin
            if(en  & N[0]) begin 
                if(cnt_b == 8'b0)begin
                    cnt_b <= N - 1;
                    clk_b <= 1'b1;
                end
                else if(cnt_b > ((N + 1)/2)) begin
                    cnt_b <= cnt_b - 1'b1 ;
                    clk_b <= 1'b1;
                end
                else begin
                    cnt_b <= cnt_b - 1'b1;
                    clk_b <= 1'b0;
                end
            end
            else begin
                clk_b <= 1'b0;
                cnt_b <= 8'b0;
            end
        end
    end


endmodule

testbench文件

module div_clk_tb();
    reg          clk;
    reg          rst_n;
    reg          en;
    reg   [7:0]    N;
    wire         clk_out;


    initial begin
        rst_n   <= 1'b1;
        #10
        rst_n  <= 1'b0;
        #10
        rst_n  <= 1'b1;
    end

    initial begin
		clk = 0;
		forever begin
			#5 clk = ~clk;
		end
	end


    
    initial begin
        #30;
        en <= 1'b1;
        N <= 8'd7;
        #300;
        N <= 8'd2;
    end


div_clk inst_div_clk_tb(
    .clk(clk),
    .rst_n(rst_n),
    .en(en),
    .N(N),
    .clk_out(clk_out)
);

endmodule

仿真结果

首先第一个是错误的图,可以看到如果奇数分频如果采用偶分频只计数半轮的方法不可行。
在这里插入图片描述
修改后可以清楚的看见仿真正确,这里要特别说明的是如果在前一种N参数分频一个周期还未结束时,如果N改变,会导致一段时钟频率的混乱。
在这里插入图片描述

任意小数分频

学习参考的任意小数分频的链接1
锁相环

对于任意小数分频,如果有PLL的话,直接倍频再分频即可;或常用的方法有双模前置小数分频和脉冲删除小数分频。前一种方法设计较为复杂,因此主要以第二种方式为主设计了一下。

这里主要通过将任意小数化为分数进行实现,首先需要理解下面的概念,我通过举例来说明:
假设我们需要实现8.7的分频,那么意思是我们先实现10分频,然后其中8.7的高电平,但通常0.*在时钟分频中不好出现,(0.5还好实现),那么我们实现的办法是在85个时钟周期中,出现10次高电平,但这高电平不是连续出现的,而说的是整体的占比,如果这样的话,就实现了87/10的时钟分频。

有一个计算公式,可以让87个周期中出现10次高电平,计算公式如下(好像称作双模前置小数分频原理)原文链接

T=8.7 对应于M.N(即M=8|N = 7)T也可以表示为 T = M + b/(a+b) 这里的a+b就是值”输出的分频信号2个时钟周期这一平均概念“将M通分至分母(a+b),则T = ( Ma+(M+1)b )/ a+b,这里我们发现组成小数分频使用了a个M分频和b个M+1分频的整数分频电路。
这个方法被称作《双模前置小数分频》其中最重要的核心是M分频和M+1分频这个相近频率

T = 8.7= 8+ 0.7 = 8+ 7/10 = = (8a + 9b )/a+b
{a + b = 10
{ma + (m+1)b = 87
这是我对这个公式的理解,其实这里a,b的取值是有多种取法的,但是公式的取法更加好理解(a + b = 10),同时要保持了最大化的50%的占空比(8和9之间的差较小),这里公式带进去之后,求得的a,b总是整数,尽管仿真图出来我觉得这种小数分频没有什么太大的意义,最终的公式如下:
{ 3 + 7 = 10
{ 8
3 + 9
7 = 85

在这里插入图片描述
参考的博主是我看的那么多将的比较清楚的了,所以我这里直接截图了,为了减少抖动,那我采取的策略是9 9 8 9 9 8 9 9 8 9 这要的顺序来产生高电平。

verilog代码

###1.1 异步复位小数计数器

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2022/06/26 15:03:38
// Design Name: 
// Module Name: fraction_divide
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module fraction_divide(
    input       clk,
    input       rst_n,  //同时练习异步复位同步释放
    output      clk_out

    );

    reg  rst_n1,rst_n2;
    reg  [4:0]  count;  //大循环用于控制偶分频还是奇分频
    reg  [4:0]  even_count; //偶分频计数
    reg  [4:0]  odd_count;  //奇分频计数
    

    assign clk_out  = (even_count == 7 || odd_count == 8);


    always@(posedge clk or negedge rst_n) begin  //0~9
        if(rst_n == 0)  begin
            count  <= 5'b0;
            even_count  <= 5'b0;
            odd_count <= 5'b0;
        end
        else if (count == 9)begin
            if(odd_count < 8)
                odd_count <= odd_count + 1'b1;
            else begin
                odd_count <= 5'b0;
                count <= 5'b0;
            end

        end

        else if (count == 2 || count == 5 || count == 8) begin
            if(even_count < 7)
                even_count <= even_count + 1'b1;
            else begin
                even_count <= 5'b0;
                count <= count + 1'b1;
            end
        end

        else if(count != 2 || count != 5 )begin
            if(odd_count < 8)
                odd_count <= odd_count + 1'b1;
            else begin
                odd_count <= 5'b0;
                count <= count + 1'b1;
            end
        end

        else begin
            count  <= 5'b0;
            even_count  <= 5'b0;
            odd_count <= 5'b0;
        end

    end

endmodule

1.2 testbench

module fraction_divide_tb();
    reg clk;
    reg rst_n;
    wire clk_out;

    fraction_divide u1 (.clk(clk),.rst_n(rst_n),.clk_out(clk_out));

    always #5 clk =~clk;

    initial
        begin
            clk = 0;
            rst_n = 1;
            #15
            rst_n = 0;
            #25
            rst_n = 1;
            #4000;
        end


endmodule

1.3仿真图

79 + 38 = 87,其中高电平出现10次,符合要求。
在这里插入图片描述
在这里插入图片描述

2.1 异步复位,同步释放的小数分频

异步复位,同步释放

在复位信号到来的时候不受时钟信号的同步,而是在复位信号释放的时候受到时钟信号的同步。

###2.2 verilog

module fraction_divide(
    input       clk,
    input       rst_n,  //同时练习异步复位同步释放
    output      clk_out

    );

    reg  rst_n1,rst_n2;
    reg  [4:0]  count;  //大循环用于控制偶分频还是奇分频
    reg  [4:0]  even_count; //偶分频计数
    reg  [4:0]  odd_count;  //奇分频计数
    
    assign reset_n = rst_n2;
    assign clk_out  = (even_count == 7 || odd_count == 8);

    always @ (posedge clk  or negedge rst_n) begin
        if (!rst_n) begin
            rst_n1 <= 1'b0;
            rst_n2 <= 1'b0;
        end
        else begin
            rst_n1 <= 1'b1;
            rst_n2 <= rst_n1;
        end
    end




    always@(posedge clk or negedge rst_n) begin  //0~9
        if(reset_n == 0)  begin
            count  <= 5'b0;
            even_count  <= 5'b0;
            odd_count <= 5'b0;
        end
        else if (count == 9)begin
            if(odd_count < 8)
                odd_count <= odd_count + 1'b1;
            else begin
                odd_count <= 5'b0;
                count <= 5'b0;
            end

        end

        else if (count == 2 || count == 5 || count == 8) begin
            if(even_count < 7)
                even_count <= even_count + 1'b1;
            else begin
                even_count <= 5'b0;
                count <= count + 1'b1;
            end
        end

        else if(count != 2 || count != 5 )begin
            if(odd_count < 8)
                odd_count <= odd_count + 1'b1;
            else begin
                odd_count <= 5'b0;
                count <= count + 1'b1;
            end
        end

        else begin
            count  <= 5'b0;
            even_count  <= 5'b0;
            odd_count <= 5'b0;
        end

    end

endmodule

2.3 仿真消除了亚稳态的同时,可以与上图对比,发现,在第一个时钟周期中能够计数没有误差。
在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值