Verilog 分频器设计

目录

 

1、偶分频

2、奇分频

3、任意分频和占空比


 

在数字电路中,使用 Verilog 生成不同频率的时钟和占空比是较为常见的一种设计,主要分为偶数分频,奇数分频,也可以任意进行分频和占空比的配置;

 

1、偶分频

偶分频电路指的是分频系数为 2、4、6、8 ... 等偶数整数的分频电路,这种是比较简单的分频方式

例如下面 divider.v 中,对输入时钟进行6分频,即假设clk 为 50MHz ,分频后的时钟频率为 (50/6) MHz。程序如下:

//rtl
module clk_even_div(
    input clk,
    input rst_n,
    output reg clk_div
);    
    parameter NUM_DIV = 6;
    reg [3:0]cnt;
    
always @(posedge clk or negedge rst_n)
    if(!rst_n) begin
        cnt     <= 4'd0;
        clk_div    <= 1'b0;
    end
    else if(cnt < NUM_DIV / 2 - 1) begin
        cnt     <= cnt + 1'b1;
        clk_div    <= clk_div;
    end
    else begin
        cnt     <= 4'd0;
        clk_div    <= ~clk_div;
    end
endmodule

testbench为:

//testbench
`timescale 1ns / 1ps
module testb_div_even;
    // Inputs
    reg clk;
    reg rst_n;
    // Outputs
    wire clk_div;

    // Instantiate the Unit Under Test (UUT)
    clk_even_div uut (
        .clk(clk), 
        .rst_n(rst_n), 
        .clk_div(clk_div)
    );
    always #10 clk = ~clk;

    initial begin
        // Initialize Inputs
        clk = 0;
        rst_n = 0;
        // Wait 100 ns for global reset to finish
        #100;
        // Add stimulus here
        rst_n = 1;
    end
endmodule

2、奇分频

由于奇分频需要保持分频后的时钟占空比为 50% ,所以不能像偶分频那样直接在分频系数的一半时使时钟信号翻转(高电平一半,低电平一半)。
接下来我们设计一个 5 分频的模块,设计思路如下:

采用计数器 cnt1 进行计数,在时钟上升沿进行加 1 操作,计数器的值为 0、1 时,输出时钟信号 clk_div 为高电平;计数器的值为2、3、4 时,输出时钟信号 clk_div 为低电平,计数到 5 时清零,从头开始计数。我们可以得到占空比为 40% 的波形 clk_div1。

采用计数器 cnt2 进行计数,在时钟下降沿进行加 1 操作,计数器的值为 0、1 时,输出时钟信号 clk_div 为高电平;计数器的值为2、3、4 时,输出时钟信号 clk_div 为低电平,计数到 5 时清零,从头开始计数。我们可以得到占空比为 40% 的波形 clk_div2。

clk_div1 和clk_div2 的上升沿到来时间相差半个输入周期,所以将这两个信号进行或操作,即可得到占空比为 50% 的5分频时钟。程序如下:

设计代码:

module clk_odd_div(
    input clk,
    input rst_n,
    output clk_div
    );

    parameter NUM_DIV = 5;
    reg[2:0] cnt1;
    reg[2:0] cnt2;
    reg    clk_div1, clk_div2;

always @(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt1 <= 0;
    else if(cnt1 < NUM_DIV - 1)
        cnt1 <= cnt1 + 1'b1;
    else 
        cnt1 <= 0;
        
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        clk_div1 <= 1'b1;
    else if(cnt1 < NUM_DIV / 2) 
        clk_div1 <= 1'b1;
    else
        clk_div1 <= 1'b0;
        
always @(negedge clk or negedge rst_n)
    if(!rst_n)
       cnt2 <= 0;
    else if(cnt2 < NUM_DIV - 1)
       cnt2 <= cnt2 + 1'b1;
    else 
       cnt2 <= 0;

always @(negedge clk or negedge rst_n)
    if(!rst_n)
        clk_div2 <= 1'b1;
    else if(cnt2 < NUM_DIV / 2) 
        clk_div2 <= 1'b1;
    else
        clk_div2 <= 1'b0;
        
    assign clk_div = clk_div1 | clk_div2;

endmodule

testbench 为;

//testbench
`timescale 1ns / 1ps
module testb_div_odd;
    // Inputs
    reg clk;
    reg rst_n;
    // Outputs
    wire clk_div;

    // Instantiate the Unit Under Test (UUT)
    clk_odd_div uut (
        .clk(clk), 
        .rst_n(rst_n), 
        .clk_div(clk_div)
    );
    always #10 clk = ~clk;

    initial begin
        // Initialize Inputs
        clk = 0;
        rst_n = 0;
        // Wait 100 ns for global reset to finish
        #100;
        // Add stimulus here
        rst_n = 1;
    end
endmodule

绿色部分是输入的时钟,红色的部分是输出的 5 分频的时钟;

黄色和白色部分是 clk_div1 和 clk_div2

 

3、任意分频和占空比

获取的任意占空比和分频系数的方式是通过直接进行输入 clk 的值进行计数,在计数器到达某时刻,直接进行输出时钟的 0/1 翻转控制;

示例代码为:

module clk_div(
    input clk,
    input rst_n,
    output reg clk_div
    );

    reg[5:0] cnt;
    parameter MAX_CNT = 8;
    parameter TOG_CNT = 2;
	
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        cnt <= 1'b0;
    else if(cnt < MAX_CNT)
        cnt <= cnt + 1'b1;
    else 
        cnt <= 1'b0;

always @(posedge clk or negedge rst_n)
    if(!rst_n)
        clk_div <= 1'b0;
    else if(cnt < TOG_CNT)
        clk_div <= 1'b1;
    else 
        clk_div <= 1'b0;

testbench 为:

module clk_div;

    // Inputs
    reg clk;
    reg rst_n;

    // Outputs
    wire clk_div;

    // Instantiate the Unit Under Test (UUT)
    clk_div uut (
        .clk(clk), 
        .rst_n(rst_n), 
        .clk_div(clk_div)
    );

    always #10 clk = ~clk;

    initial begin
        // Initialize Inputs
        clk = 0;
        rst_n = 0;

        // Wait 100 ns for global reset to finish
        #100;
        
        // Add stimulus here
        rst_n = 1;
	end
      
endmodule

黄色部分为分频出来的时钟;

 

参考:

https://www.cnblogs.com/zhangxianhe/p/11083208.html

  • 43
    点赞
  • 306
    收藏
  • 打赏
    打赏
  • 6
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论 6

打赏作者

爱洋葱

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值