• 【Verilog】时钟奇分频实战经验


    分频操作重点(计数器参数、触发条件、占空比

    1. N分频表示:主时钟clk打N拍,分频后时钟打一拍。
      【一拍:乐理中“一上一下”为一拍。在此处即形容clk的一个上升沿和一个下降沿,非常形象。】

    2. 用计数器cnt计数:可以选择“仅在clk上升沿计数”,也可以选择“在clk上升沿和下降沿都计数”。对于博主而言,在进行时钟奇分频时,我更倾向于使用后者,即上升沿和下降沿都计数,这样操作难度会小一些。

    仅在clk上升沿计数:每个周期需要计数N-1次。每个周期从0开始,到N-1结束。

    一个周期内clk要打N拍,每一拍有一个上升沿,每个上升沿计数+1。所以N拍计数+N。最后一拍衔接下一周期的第一拍,上升沿属于下一个周期,计数-1。所以最终需要计数N-1。

    在clk上升沿和下降沿都计数:每个周期要计数2N-1次

    一个周期内clk要打N拍,每一拍有一个上升沿和一个下降沿,每个上升沿和下降沿都计数+1。所以N拍计数+2N。最后一拍衔接下一周期的第一拍,上升沿属于下一个周期,下降沿还属于本周期,所以计数-1。所以最终需要计数2N-1。

    我们也可以通过画图加推倒,很清楚地来解释,比如我现在要实现5分频(占空比40%):
    请添加图片描述

    1. 奇分频的时钟边沿触发,必须是上升沿和下降沿同时作为敏感列表的。因为奇分频会产生0.5拍,即仅仅越过半个clk周期的一个边沿,这个时候很有可能是下降沿。
      【说的比较抽象,一会儿实例上了就知道了】

    2. 占空比控制:抓住电平反转时cnt的值。画图即可解出。


    实例——7分频,占空比50%

    在这里插入图片描述
    波形分析:
    在这里插入图片描述
    可以看到:
    ①计数周期:2N-1=13。
    ②为了满足占空比50%,电平反转的点为:6和13。

    经过分析,代码非常简单:
    ①计数器参数定义:

    parameter FD = 7;   //分频数
    parameter CNT_MAX_NUM = 2*FD - 1;   //计数器最大计数14-1=13
    parameter CHANGE_NUM_1 = 6;  //电平反转的cnt值
    parameter CHANGE_NUM_2 = 13;  //电平反转的cnt值
    
    • 1
    • 2
    • 3
    • 4

    ②计数器cnt控制块:

    reg [3:0] cnt_ctrl;
    always@(posedge clk_in or negedge clk_in or negedge rst)
    begin
        if(!rst)    cnt_ctrl <= 0;
        else    cnt_ctrl <= (cnt_ctrl == CNT_MAX_NUM) ? 0 : (cnt_ctrl + 1);
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    ③分频后时钟电平控制:

    reg clk_temp;
    always@(posedge clk_in or negedge clk_in or negedge rst)
    begin
        if(!rst)    clk_temp <= 0;
        else    clk_temp <= (cnt == 1 || cnt == 5) ? ~clk_temp : clk_temp;
    end
    
    assign clk_out5 = clk_temp;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代码心得总结:

    多用三目运算符?:取代if else,能大幅度简化代码的复杂度
    ②wire型不能直接在always内操作,但是reg型变量可以赋值给wire。我们可以定义一个reg型变量参与always的操作,再把这个值assign给wire变量。(比如本代码中的clk_temp)
    学会用parameter定义和强调一些常量,如同c语言的define一样,很方便也有很高的可读性。

    完整代码:

    module odo_div_or
       (
        input    wire  rst ,
        input    wire  clk_in,
        output   wire  clk_out7
        );
    
    //*************code***********//
    parameter FD = 7;   //分频数
    parameter CNT_MAX_NUM = 2*FD - 1;   //计数器最大计数14-1=13
    parameter CHANGE_NUM_1 = 6;  //电平反转的cnt值
    parameter CHANGE_NUM_2 = 13;  //电平反转的cnt值
    
    reg [3:0] cnt_ctrl;
    always@(posedge clk_in or negedge clk_in or negedge rst)
    begin
        if(!rst)    cnt_ctrl <= 0;
        else    cnt_ctrl <= (cnt_ctrl == CNT_MAX_NUM) ? 0 : (cnt_ctrl + 1);
    end
    
    reg clk_temp;  //reg型,暂存分频溢出。
    always@(posedge clk_in or negedge clk_in or negedge rst)
    begin
        if(!rst)    clk_temp <= 0;
        else    clk_temp <= (cnt_ctrl == CHANGE_NUM_1 || cnt_ctrl == CHANGE_NUM_2) ? (~clk_temp) : (clk_temp);
    end
    
    assign clk_out7 = clk_temp;
    //*************code***********//
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    经验总结

    时序图多画多分析,多debug!

  • 相关阅读:
    数据结构习题--杨辉三角形(返回某一行)
    网络安全(黑客)自学
    有没有看下concat函数这个符号报错问题?应该是网站自己的问题?
    基于ChatGPT打造安全脚本工具流程
    论文解析[5] nnU-Net: Breaking the Spell on Successful Medical Image Segmentation
    golang小案例获取命令行的的参数并求得最大值
    [蓝桥杯 2021 省 AB] 砝码称重
    Cesium加载geoserver发布的arcgis切片 4326坐标系
    pdf添加水印
    Python中如何将列表中的所有项转换为float?(含代码讲解)
  • 原文地址:https://blog.csdn.net/GalaxyerKw/article/details/127520145