当前位置: 首页 > news >正文

Verilog和FPGA的自学笔记9——呼吸灯

昨晚刚做了个呼吸灯,感觉挺不错的,给大家分享一下(打call打call)

呼吸灯还是很经典的,之前无论学什么嵌入式,在定时器PWM部分总是先拿这玩意开刀(doge)

先谈谈个人体会。
嵌入式定时器部分利用递增的计数器来调节占空比(即PWM),来实现呼吸灯,而再FPGA里,我们就是从头搭建一个计数器,然后类似的通过计数器中的值来递增或递减占空比。

1.原理分析

思路还是很清晰的哈,把大体模块先说下:

如果从全灭到全亮需要2s,我们可以设置1000个亮度,每个亮度显示2ms;接着把每个亮度分成1000等分,每个等分2us。这1000个2us有的需要led亮,有的需要led灭。这最小的1000等分就是PWM占空比的最小单位。

反正我看了好几次才明白啥意思,所以再给大家放张图解释一下:
在这里插入图片描述
大家看到下面的led脉冲比,可以发现占比的最小单位是2us,也就是说,再我们的系统中,2us是时间的最小单位。之后,2ms在2us的基础上计数,2s在2ms基础上计数。

而为什么要把2ms再次打散呢?因为你要想实现PWM,把每2ms作为一个亮度,那就不能在ms级上操作(因为每2ms中需要led有亮有灭),所以我们再把2ms分成1000分,在us级上操作led,这样对于更宏观的ms级就是不同亮度了。

2.敲代码……

我们先考虑一下顶层模块:

module breath(input sys_clk,input sys_rst,output reg led
);endmodule

很简单哈,除了时钟和复位的输入,就是led的输出了。

基于上面的原理,需要我们先把2us的块写出来。

reg [6:0] cnt;
parameter CNT  = 7'd100;always @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst)cnt <= 7'd0;else if(cnt < CNT - 7'd1)cnt <= cnt + 7'd1;elsecnt <= 7'd0;
end

打过流水灯和按键消抖这些新手村后,计数器这种小case对咱们这些大佬 小白 来说肯定时毫无难度了哈!不过有一点我觉得可以分享一下。

写C时的循环长这个德行:

  • for(int i=0;i<CNT;i++)

这样就循环了CNT次。

但Verilog里不是这样啊!因为for语句里的i++是在循环结束后对i进行++,而always块里是立即执行,也就意味着如果你还这么(cnt < CNT)写,那就会执行CNT+1次,这肯定不是我们所期望的,所以我在if里多减了1。

还有,虽然我们现在可以在例化模块时传参,但把最大值定位为参数,可以使代码更简洁可读,推荐这样做。

接下来我们做ms级和s级模块。

ms和s的难点在于,你需要将cnt_2ms和cnt_2s在最大值时清零。相比之下cnt_2us好办,因为cnt_2us清零本来就是if当中的一种情况。但是!!

cnt_2ms的清零如果也像us级那样写,就像下面这样:

always @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst)cnt2 <= 10'd0;else if(cnt == CNT - 7'd1)cnt2 <= cnt2 + 10'd1;elsecnt2 <= 10'b0 ;end

仿真出来就会这样:
在这里插入图片描述
会发现cnt_2ms压根连3都数不到!

所以cnt_2ms的清零是有额外条件的,不能简单把它扔到else里。

一种理解方式是:需要cnt_2ms数最大值时,才能允许清零。
所以我们可以这样写:

if(!sys_rst || (cnt2 > CNT2))cnt2 <= 10'd0;

另一种理解方式是从波形图中来的:当cnt_2ms和cnt_2us都数最大值时,才允许清零。

if(!sys_rst_n || (cnt_2ms == (CNT_2MS_MAX - 10'b1)&& (cnt_2us == (CNT_2US_MAX - 7'b1))))cnt_2ms <= 10'b0;

我把相关字加粗了,大家仔细理解一下~

这两种方式实现的效果难道有区别吗??
别急~ 我们仿真看一下,第一种:
在这里插入图片描述
第二种:
在这里插入图片描述
区别很明显了吧……
(悄悄说一句其实第一种这种蹩脚的操作是我写的……)
咳咳,毋庸置疑,第一种也是可以完美实现的!!稀烂
事后我就开始琢磨,为啥我没想到第二种写法呢?
哎~ 其实我刚刚已经透露一点点了。

另一种理解方式是从波形图中来的

个人观点:我是按循环的思路来写的,第二种是按信号状态写的。或许在某种意义上,我仍深陷于软件编程的泥沼……

一起努力吧!

s级和ms级计数器一样一样的,就不废话啦,相信大家现在已经做出来从全灭到全亮的程序啦~

对于逆向过程,只需要设置一个标志位,然后根据标志位对led进行状态翻转即可,也没啥太大难度,大家自己改改调试一下就好。

之前看过不少程序思路分享,我就发现昂,大部分文章中的代码都是一截截的,这样做固然有道理,因为讲解得一段段讲。但对初学者就很不友好,因为我们大部分在学的时候几乎没有能力构建起程序框架,只会抄。所以在这个阶段,我们可能连拼出完整代码的机会都没有。

于是,我决定把整个代码给大家贴出来:

module breath(input sys_clk,input sys_rst,output reg led
);reg [6:0] cnt_2us;
reg [9:0] cnt_2ms;
reg [9:0] cnt_2s;reg flag;parameter CNT_2US = 7'd100;
parameter CNT_2MS = 10'd1000;
parameter CNT_2S = 10'd1000;always @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst)cnt_2us <= 7'd0;else if(cnt_2us < CNT_2US - 7'd1)cnt_2us <= cnt_2us + 7'd1;elsecnt_2us <= 7'd0;endalways @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst || ((cnt_2ms == CNT_2MS - 10'd1) &&(cnt_2us == CNT_2US - 7'd1)))cnt_2ms <= 10'd0;else if(cnt_2us == CNT_2US - 7'd1)cnt_2ms <= cnt_2ms + 10'd1;elsecnt_2ms <= cnt_2ms;endalways @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst)begincnt_2s <= 10'd0;flag <= 1'b1;endelse if((cnt_2us == CNT_2US - 7'd1) &&(cnt_2ms == CNT_2MS - 10'd1)&&(cnt_2s  == CNT_2S  - 10'd1))begincnt_2s <= 10'd0;flag <= ~flag;endelse if(cnt_2ms == CNT_2MS - 10'd1 && cnt_2us == CNT_2US - 7'd1)cnt_2s <= cnt_2s + 10'd1;elsecnt_2s <= cnt_2s;endalways @(posedge sys_clk or negedge sys_rst) beginif(!sys_rst)led <= 1'b0;else if(cnt_2ms < cnt_2s)beginif(flag)led <= 1'b1;elseled <= 1'b0;endelse beginif(flag)led <= 1'b0;elseled <= 1'b1;endendendmodule

我在改代码的过程中,遇到了一些问题,在这里总结一下,也是给大家填填坑~

  1. 还是多驱动源的问题,不要在多个always块里给一个信号赋值,比如程序中flag的复位,本来放哪里都可以,但因为翻转逻辑在2s那里,所以我写在那。
  2. cnt_2s清零的条件注意一下,需要当cnt_2us、cnt_2ms和cnt_2s同时达到最大值-1时执行,所以 if 中需要三个条件

仿真波形也很好看:
在这里插入图片描述

看到板子上小灯丝滑过度,心里很开心的~~

本文不长,这次的分享也算是对计数器应用的进一步深入,也希望大家能通过练习这个小demo进一步获得水平的提升!

不知道后面会先写状态机还是IP核,可能又要闭关一段时间了,大家期待吧~~

如果有不明白或错误之处,也希望大家在评论区给出,帮助大家的同时也能再次提升自己对于FPGA和Verilog的理解,感谢大家!!

系列链接:
上一篇:Verilog和FPGA的自学笔记8——按键消抖与模块化设计
下一篇:码字ing……

http://www.dtcms.com/a/558053.html

相关文章:

  • @RestController注解
  • 门户网站英文郑州网站模板建设
  • LVS负载均衡集群理论
  • 关于高校网站建设论文的总结网络优化基础知识
  • 规则引擎Drools语法要点
  • 柘林网站建设公司推广做哪个网站
  • 校园网站建设情况统计表logo标志
  • UVa 10396 Vampire Numbers
  • 关于网站建设的指标河北城乡和住房建设厅官方网站
  • 【图像】图像的颜色深度(Color Depth)和存储格式(File Format)
  • docker镜像国内的仓库地址
  • 汕头企业网站建设价格seo外贸 网站公司推荐
  • 跟着deepseek减肥
  • 深圳盐田网站建设wordpress vr主题公园
  • 未来软件网站建设财经网站直播系统建设
  • 预测海啸:深入探索地震模式(2001-2022年)
  • 【AutoHotkey】(解决记录)AHK安装后脚本显示运行实际没执行(最简单的测试用脚本)
  • 智慧教室解决方案(3)PPT(48页)
  • 个人作品集网站wordpress置顶重复
  • 【模拟面试|豆包模拟面试-2 Java基础】
  • 长沙网站维护外贸做什么产品出口好
  • VBA数据库解决方案第二十四讲:把提供的数据在数据表中删除
  • 大模型数据集的深入认识和微调数据集的构建流程
  • 怎么在欧美做网站推广网站通栏广告代码
  • 网站建设 永灿 竞争娱乐网站建设公司
  • 百度开放云搭建网站中学加强校园网站内容建设
  • 【智能体】之从战场到厅堂
  • 《云存储服务》
  • C#中通过get请求获取api.open-meteo.com网站的天气数据
  • 策划方案免费网站中国建设银行官网版本