【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值

②计数器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;
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;

代码心得总结:

多用三目运算符?:取代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


经验总结

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值