verilog呼吸灯实验-基于zynq7020

在学fpga,刚开始入门,学习到了一个呼吸灯的实验,是基于PWM脉冲宽度调制进行灯的控制。编程方法有很多,网上也有很多教程,我这里只是记录一下在学习编写基本代码时遇到的一个问题,以便以后复习回顾。
我在网上学习的开源代码就是利用计数器产生一个4s一个周期的呼吸灯,分为2s渐亮2s渐灭,主要就是用时钟来产生不同周期的计数器,将两秒分为1000份,每份2毫秒,再将2毫秒分为1000份,每份2微妙,这样就可以在每个2毫秒递增的基础上,以2微妙4微妙6微妙……的节奏逐渐扩大(减小)一个时间空窗内等点亮的程度,从而实现平滑的呼吸灯效果。
核心代码直接放在下面,其他帖子也有讲的,我就不再总结

module breath_led (
    input         clk,
    input         rstn,
    output reg    led
);

    reg [6:0] cnt_2us;
    reg [9:0] cnt_2ms;
    reg [9:0] cnt_2s;
    reg       inc_dec_flag;  //0:递增,1:递减

    parameter CNT_2US_MAX = 7'd100;
    parameter CNT_2MS_MAX = 10'd1000;
    parameter CNT_2S_MAX = 10'd1000;

    //计数器2微秒
    always@(posedge clk or negedge rstn) begin
        if(!rstn)
            cnt_2us <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1))
            cnt_2us <= 0;
        else
            cnt_2us <= cnt_2us + 1;
    end

    //计数器2毫秒
    always@(posedge clk or negedge rstn) begin
        if(!rstn)
            cnt_2ms <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1)  && cnt_2ms == (CNT_2MS_MAX - 1))
            cnt_2ms <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1))
            cnt_2ms <= cnt_2ms + 1;
        else
            cnt_2ms <= cnt_2ms;
    end

    //计数器2秒
    always@(posedge clk or negedge rstn) begin
        if(!rstn)
            cnt_2s <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1)  && cnt_2ms == (CNT_2MS_MAX - 1) && cnt_2s == (CNT_2S_MAX - 1))
            cnt_2s <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1)  && cnt_2ms == (CNT_2MS_MAX - 1))
            cnt_2s <= cnt_2s + 1;
        else
            cnt_2s <= cnt_2s;
    end
    
    //递增、递减标志位
    always@(posedge clk or negedge rstn) begin
        if(!rstn)
            inc_dec_flag <= 0;
        else if(cnt_2us == (CNT_2US_MAX - 1)  && cnt_2ms == (CNT_2MS_MAX - 1) && cnt_2s == (CNT_2S_MAX - 1))
            inc_dec_flag <= ~inc_dec_flag;
        else
            inc_dec_flag <= inc_dec_flag;
    end

    //呼吸灯
    always@(posedge clk or negedge rstn) begin
        if(!rstn)
            led <= 0;
        else if(inc_dec_flag == 0 && cnt_2ms <= cnt_2s)
            led <= 1;
        else if(inc_dec_flag == 1 && cnt_2ms >= cnt_2s)
            led <= 1;
        else
            led <= 0;
    end

endmodule

我主要记录一下对最后几行代码的理解,就是这里

always@(posedge clk or negedge rstn) begin
        if(!rstn)
            led <= 0;
        else if(inc_dec_flag == 0 && cnt_2ms <= cnt_2s)
            led <= 1;
        else if(inc_dec_flag == 1 && cnt_2ms >= cnt_2s)
            led <= 1;
        else
            led <= 0;
    end

在这里,用标志位inc_dec_flag来判定是渐亮还是渐灭,这个还好理解,当inc_dec_flag==0时为渐亮,但后面cnt_2ms <= cnt_2s我一开始不是很理解,为什么只要cnt_2ms小于等于cnt_2s时直接就可以判定led为1了?因为在我初期的理解中,cnt_2ms很大程度上都会小于cnt_2s,那不就是说等不会脉冲调频了?
一开始不理解,后来看了仿真波形图才明白怎么回事。为了便于仿真,源代码里的参数进行了缩小,
在这里插入图片描述
在红色箭头标注的两行,就是cnt_2ms以及cnt_2s,cnt_2ms可以说是比cnt_2s“变化的速率快”,cnt_2ms变化10个,cnt_2s才能变化一次,因此从最开始开始看,当cnt_2s为0时,cnt_2ms逐渐增加,在这个阶段中,只有当cnt_2ms为0时才是满足cnt_2ms小于等于cnt_2s的,因此灯亮一个cnt_2ms的时间;cnt_2s为1时,cnt_2ms又来一遍,从0开始逐步增加到9,这时只有cnt_2ms为0和1时才满足cnt_2ms小于等于cnt_2s,因此这时灯会亮两个cnt_2ms的时间……
后面以此类推,也就是为什么要写成如上所示代码的形式。
但看波形图,可以看到led点亮的时间并不是严格对齐cnt_2ms为000或者000 001的,而是错开了一位,我想这是灯必须等下一个时钟到来才能亮的原因吧。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值