FPGA——时钟分频

时钟分频也是笔试题里面经常出现的,(我已经遇到过了),看完这一篇,分分钟掌握!

目录

偶数分频

D触发器级联法

 计数器法

奇数分频

占空比50% 的奇数分频

占空比无要求的奇数分频

任意小数分频


偶数分频

FPGA——时钟分频_第1张图片 如上图输入给clk,输出将其变成周期为2倍的clk_out2, 将其变成周期为4倍的clk_out4,将其变成周期为8倍的clk_out8,占空比为50%

D触发器级联法

对于偶数分频电路,在不考虑时钟同步时钟延迟的问题时,直接使用D触发器级联来实现:关键在于,上升沿才能触发翻转,但是一个周期只有一个上升沿,因此周期翻倍

FPGA——时钟分频_第2张图片

`timescale 1ns/1ns

module even_div
    (
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out2,
    output    wire clk_out4,
    output    wire clk_out8
    );

    reg clk_out2_r, clk_out4_r, clk_out8_r;
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            clk_out2_r <= 0;
        else
            clk_out2_r <= ~clk_out2_r;
    end
    
    always@(posedge clk_out2 or negedge rst) begin
        if(~rst)
            clk_out4_r <= 0;
        else
            clk_out4_r <= ~clk_out4_r;
    end
    
    always@(posedge clk_out4 or negedge rst) begin
        if(~rst)
            clk_out8_r <= 0;
        else
            clk_out8_r <= ~clk_out8_r;
    end
    
    assign clk_out2 = clk_out2_r;
    assign clk_out4 = clk_out4_r;
    assign clk_out8 = clk_out8_r;

endmodule

 计数器法

2、4、8恰好是2的次方,可构造一个3位计数器,依靠第0位,第1位,第2位的变化速度来实现:

2分频的输出=cnt第0位(由于计数器在clk=高电平时才+1,因此本身就是2倍的周期)

4分频输出=cnt第1位

8分频输出=cnt第2位

eg 4分频:000 001 010 011 100 101 110 111 000

`timescale 1ns/1ns
module even_div
    (
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out2,
    output    wire clk_out4,
    output    wire clk_out8
    );


    reg [2:0]cnt;
    always@(posedge clk_in or negedge rst)
        if(!rst)
            cnt <= 3'b111;//初始赋全1
    else
        cnt <= cnt+1;
    
    assign clk_out2 = ~cnt[0];//根据波形,一开始全为高电平
    assign clk_out4 = ~cnt[1];
    assign clk_out8 = ~cnt[2];
endmodule

奇数分频

占空比50% 的奇数分频

设计一个同时输出7分频的时钟分频器,占空比要求为50% 

对于奇数分频电路,主要难点在于50%占空比的实现。单触发沿在奇数分频中是没有办法实现50%占空比的,因此需要考虑使用双边沿加组合逻辑实现50%占空比

FPGA——时钟分频_第3张图片

设置计数器,计数器从0→6,当计数器==3,上升沿触发得到clk_pos,下降沿触发得到clk_neg,

而输出的7分频clk,上升沿在clk_neg触发,下降沿在clk_pos触发,是clk_neg和clk_pos进行或运算的结果

根据这个思路,我们可以得到任意奇数分频,占空比为50%的输出,修改N值即可,代码如下:

`timescale 1ns/1ns


module odo_div_or
  #(parameter N = 7)
   (
    input    wire  rst ,
    input    wire  clk_in,
    output   wire  clk_out7
    );



   reg [3:0]            cnt ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         cnt    <= 'b0 ;
      end
      else if (cnt == N-1) begin
         cnt    <= 'b0 ;
      end
      else begin
         cnt    <= cnt + 1'b1 ;
      end
   end

   reg                  clkp ;
   always @(posedge clk_in or negedge rst) begin
      if (!rst) begin
         clkp <= 1'b0 ;
      end
      else if (cnt == (N>>1)) begin 
        clkp <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkp <= 0 ;
      end
   end
  

   reg                  clkn ;
   always @(negedge clk_in or negedge rst) begin
      if (!rst) begin
         clkn <= 1'b0 ;
      end
      else if (cnt == (N>>1) ) begin 
        clkn <= 1 ;
      end
      else if (cnt == N-1) begin 
        clkn <= 0 ;
      end
   end


   assign clk_out7 = clkp | clkn ;


endmodule

占空比无要求的奇数分频

实现一个5分频clk,占空比可修改

由于一个cnt其实=2个clk_in ,所以在占空比不要求的情况下,即使是奇数分频也=一个偶数,我们可以把这个偶数分成2个偶数的和,(例如5分频相当于10clk_in,10=4+6,可以4clk_in低电平,6clk_in高电平)(而要求占空比的时候,10=5+5,需要参考上面的做法)

一个完整的clk周期要包含5个clk_in,但是占空比不要求,那么设置一个计数器cnt,计数范围0-4,每个clk_in周期加1。当计数器数值在0~1时,clk_out5==1;当计数器数值在2~4时,clk_out5==0。这样就实现了周期为5、占空比为3/5 ​的clk_out5

`timescale 1ns/1ns

module odd_div (    
    input     wire rst ,
    input     wire clk_in,
    output    wire clk_out5
);

    reg [2:0] cnt;
    reg clk_out5_r;
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            clk_out5_r <= 0;
        else
            clk_out5_r <=1;
    end
    
    always@(posedge clk_in or negedge rst) begin
        if(~rst)
            cnt <= 0;
        else
            cnt <= cnt==4? 0: cnt+1;
    end
    
    assign clk_out5 = clk_out5_r;

endmodule

任意小数分频

FPGA——时钟分频_第4张图片

FPGA——时钟分频_第5张图片

 小数分频器是分频器中最难的一种,而且不能像整数分频那样得到均匀且占空比为50%的分频输出

FPGA——时钟分频_第6张图片

FPGA——时钟分频_第7张图片

FPGA——时钟分频_第8张图片

`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

你可能感兴趣的:(fpga开发)