问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Verilog时钟分频模块设计详解

创作时间:
作者:
@小白创作中心

Verilog时钟分频模块设计详解

引用
CSDN
1.
https://blog.csdn.net/Adidas112233/article/details/109169393

时钟分频是数字电路设计中的一个基本且重要的功能,广泛应用于各种电子系统中。本文将详细介绍如何使用Verilog语言实现时钟分频模块,包括偶分频、奇分频以及任意占空比的任意分频。

1 偶分频模块

偶分频模块设计较为简单,首先确定分频系数M和计数器值N:

$$
M = \frac{时钟输入频率}{时钟输出频率}
$$

$$
N = \frac{M}{2}
$$

若输入时钟是50Mhz,输出时钟是1hz,则M=50_000_000,N=25_000_000。

偶分频则意味着M是偶数。

以M=4,N=2为例,希望得到的输出时钟时序如下:

因此只需要将counter以clk_in为时钟驱动计数,当counter = (N-1)时,clk_out翻转即可。

module clock_div(
    input clk,
    input rst,
    output reg clk_out
);
parameter N = 26'd25_000_000 , WIDTH = 25;
reg [WIDTH:0] counter;
always @(posedge clk or negedge rst) begin
    if (~rst) begin
        counter <= 0;
        clk_out <= 0;
    end
    else if (counter == N-1) begin
        clk_out <= ~clk_out;
        counter <= 0;
    end
    else
        counter <= counter + 1;
end
endmodule

2 奇分频模块

奇分频需要通过两个时钟共同得到,首先得到分频系数M和计数器值N:

$$
M = \frac{时钟输入频率}{时钟输出频率}
$$

$$
N = \frac{M-1}{2}
$$

如输入时钟为50M,输出时钟为10M,则M=5,N=2。

奇分频则意味着M为奇数。

以M=5,N=2为例,我们希望得到的输出时钟时序如下:

其中clk_out为最终输出时钟,clk_out1和clk_out2为辅助时钟生成。

计数器counter由0计数至(M-1)。

clk_out1在clk_in的上升延跳变,条件是counter==(N-1)或(M-1)。

clk_out2在clk_in的下降延跳变,条件是counter==(N-1)或(M-1)。

之后

clk_out = clk_out1 & clk_out2

即可得到M分频的时钟。

verilog代码如下,其中WIDTH为(N的位宽-1):

module time_adv_odd(
    input clk,
    input rst,
    output clk_out
);
parameter N = 2,WIDTH = 7;
reg [WIDTH:0] counter;
always @(posedge clk or posedge rst) begin
    if (rst) begin
        // reset
        counter <= 0;
    end
    else if (counter == (N << 1)) begin //M-1处跳变,因为 M - 1 = 2 * N,这里等于4
        counter <= 0;
    end
    else begin
        counter <= counter + 1;
    end
end
reg clk_out1;
always @(posedge clk or posedge rst) begin //clk_out1在clk_in的上升延跳变
    if (rst) begin
        // reset
        clk_out1 <= 0;
    end
    else if (counter == N-1) begin //N-1处跳变,这里等于1
        clk_out1 <= !clk_out1;
    end
    else if (counter == (N << 1)) begin //M-1处跳变,这里等于4
        clk_out1 <= !clk_out1;
    end
end
reg clk_out2;
always @(negedge clk or posedge rst) begin //clk_out2在clk_in的下降延跳变
    if (rst) begin
        // reset
        clk_out2 <= 0;
    end
    else if (counter == N-1) begin
        clk_out2 <= !clk_out2;
    end
    else if (counter == (N << 1)) begin
        clk_out2 <= !clk_out2;
    end
end
assign clk_out = clk_out1 & clk_out2;
endmodule

3 任意占空比的任意分频

在verilog程序设计中,我们往往要对一个频率进行任意分频,而且占空比也有一定的要求这样的话,对于程序有一定的要求。

现在在前面两个实验的基础上做一个简单的总结,实现对一个频率的任意占空比的任意分频。

比如: FPGA系统时钟是50M Hz,而我们要产生的频率是880Hz,那么,我们需要对系统时钟进行分频。很容易想到用计数的方式来分频:50000000/880 = 56818。

显然这个数字不是2的整幂次方,那么我们可以设定一个参数,让它到56818的时候重新计数就可以实现了。程序如下:

//rtl
module div(
    clk, 
    rst_n,
    clk_div
);
    input clk,rst_n;
    output clk_div;
    reg clk_div;
    
    reg [15:0] counter;

always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        counter <= 0;
    else if(counter==56817) 
        counter <= 0;
    else 
        counter <= counter+1;

   assign clk_div = counter[15];
endmodule

分频的应用很广泛,一般的做法是先用高频时钟计数,然后使用计数器的某一位输出作为工作时钟进行其他的逻辑设计,上面的程序就是一个体现。

下面我们来算一下它的占空比:

我们清楚地知道,这个输出波形在counter为0到32767(2的14次方)的时候为低,在32768到56817的时候为高,占空比为40%多一些,如果我们需要占空比为50%,那么我们需要再设定一个参数,使它为56817的一半,使达到它的时候波形翻转,就可以实现结果了。

程序如下:28408=56818/2-1,计数到28408就清零,翻转,其余的计数期间,保持不变。

设计代码:

//rtl
module div(
    clk, 
    rst_n,
    clk_div
);
    input clk,rst_n;
    output clk_div;
    reg clk_div;
    reg [14:0] counter;
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        counter <= 0;
    else if(counter==28408)
        counter <= 0;
    else 
        counter <= counter+1;

always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        clk_div <= 0;
    else if(counter==28408) 
        clk_div <= ~clk_div;
endmodule

继续让我们来看如何实现任意占空比,比如还是由50M分频产生880Hz,而分频得到的信号的占空比为30%。

56818×30%=17045

设计代码:

//rtl
module div(
    clk,
    rst_n,
    clk_div,
    counter
);
    input clk,rst_n;
    output clk_div;
    reg clk_div;
    output [15:0] counter;
    reg [15:0] counter;
    
always @(posedge clk)
    if(!rst_n) 
        counter <= 0;
    else if(counter==56817) 
        counter <= 0;
    else counter <= counter+1;

always @(posedge clk)
  if(!rst_n) 
         clk_div <= 0;
  else if(counter<17045) 
         clk_div <= 1;
  else 
         clk_div <= 0;
 endmodule
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号