[FPGA]Verilog利用PWM调制巧妙完成RGB三色彩虹呼吸灯(给简约的题目以美妙的解答)
概述
实现彩虹呼吸灯
题目就是这么简短,但这是目前我碰到的最有意思的一道题目,因为他有无数种解决方法,并且每一种都是那么高级或者巧妙,比如
- 可以利用3路不同初相的PWM调制信号驱动三颗RGB灯重叠呼吸
- 利用1路PWM信号以及状态机,将一个周期分为3个状态,分别是[R降G升B灭],[R灭,G降,B升]和[R升,G灭,B降],依次往复实现重叠呼吸
- 将PWM拆分为3段,分别为升,降,灭,在不同时间周期性的输送给RGB实现重叠呼吸
当然,不只这几种,还有更高级的方法或者生成语句也可以更加简练的完成题目,在这里,我将采取上面罗列的几种方法的一种折中方案,采取"拆分PWM","三元运算符实现单行条件信号分配","监视模块内运行情况并以监视信号作为状态转换的触发条件"来实现彩虹呼吸灯.
题目分析
题目只有七个字:"实现彩虹呼吸灯",其中"呼吸两个字",已经确定了这个实验和脉宽调制扯不开干系,另外"彩虹"也说明这个实验需要很多的色彩,单单靠单色LED是完成不了的,一定需要三色RGB完成,并且只是让R,G,B三个LED交替呼吸,也达不到"彩虹"的效果,所以需要让三色灯按照一定的规律重叠呼吸,这里为了方便,我按照下图示意的样式进行编程
(抱歉画工实在欠缺,咳咳)
意思就是在R灯最亮时,G灯开始升,R灯开始降,在G灯最亮时,R灯已灭,B灯开始升,G灯开始降,以此类推.
通过这个图也可以容易的分成三个情况,用以实现状态机.
PWM
PWM是个啥?
PWM( Pulse width modulation )就是脉冲宽度调制,是一种通过数字信号对模拟信号控制的有效技术.简单来说,规律的进行脉宽调制,比如将一束方波的占空比不断减小,那么这束方波的有效值也相应的减小,占空比增大,有效值也增大,借此来对LED的亮度进行控制,加以周期性的增减,即可实现呼吸灯.
呼吸灯只是PWM的一个具体应用.
PWM咋实现?
在之前的学习早已接触过PWM调制的实现方法,在这里直接给出代码,可以通过注释回忆PWM实现过程
module PWM
(input CLK
,input FLAG//标志位,控制输出的PWM是升还是降(1升0降)
,output STT//监视信号(脉冲)
,output PWM
);
reg[24:0]cnt1;
reg[24:0]cnt2;
parameter freq=2400;//通过这个freq来控制PWM的周期
reg stt;//监视状态
always@(posedge CLK)
if(cnt2==freq-1)//cnt2满,则状态为1(只持续一个时钟周期)
stt<=1'b1;
else
stt<=1'b0;
assign STT=stt;
always@(posedge CLK)
if(cnt1>=freq-1)//满则清零
cnt1<=1'b0;
else
cnt1<=cnt1+1'b1;
always@(posedge CLK)
if(cnt1==freq-1)//cnt1满,以cnt1从空到满为一个周期执行操作
if(FLAG)//升的情况
if(cnt2>=freq-1)
cnt2<=1'b0;
else
cnt2<=cnt2+1'b1;//升
else//降的情况
if(cnt2<=0)
cnt2<=freq-1;
else
cnt2<=cnt2-1'b1;//降
else
cnt2<=cnt2;
assign PWM=(cnt1<cnt2)?1'b0:1'b1;//PWM的核心,输出调制好的PWM信号
endmodule
本代码参考此网页,内有更详细的图片和讲解
代码中的stt
和STT
是监视脉冲,不影响PWM输出;输入信号FLAG
控制PWM输出信号是升还是降.二者作用在顶层代码处详细解释.
顶层模块
PWM很容易实现,需要动脑子的就是如何通过例化模块来实现交替呼吸.下面给出我的算法.
例化模块
先看代码
wire UP;
wire DW;
wire STT0;
wire STT1;
PWM up(CLK,1,STT0,UP);
PWM dw(CLK,0,STT1,DW);
其中up
例化模块中的1
代表FLAG
,在此表示这个up
例化模块是一个"升"模块,即为可以产生控制LED亮度从灭到亮的PWM信号,dw
例化模块则代表可以产生一个可以控制从亮到暗的PWM信号.通过这个设计可以将PWM模块的功能拆分,提供两种模式供主模块灵活调用.
代码中的UP
和DW
分别为代表亮度升和亮度降的PWM信号.
状态分析
这里不按照文首的那种状态机思路来写,而是将RGB三色灯分成3路对待,这里先以R为例.
对R来说,他的亮灭规律为:升(一单位时间),降(一单位时间),灭(一单位时间).然后可以以此来写条件语句进行信号分配,可能第一时间想到的就是直接定义一个分频,不同时间显示不同状态即可,但是这种写法不利于后期拓展,易读性和可维护性也稍差,在这里采用很方便的"三元运算符"解决.先来看这段代码
reg[1:0]flag0=2'b00;
always@(posedge STT0)
if(flag0==2'b10)
flag0<=1'b0;
else
flag0<=flag0+1'b1;
这里定义了一个标志为flag0
,它是以上文提到过的监视脉冲STT
为触发进行递增计数的,STT
是一个在PWM模块内每一个工作周期完成后就输出一单位时间高电平的监视脉冲,通过这个脉冲可以知道PWM已经工作完一个周期,可以进行下一周期的工作,在顶层代码里则充当了状态转移的触发条件.
再来看这一行代码
assign LED[0]=(flag0==2'b00)?UP:((flag0==2'b01)?DW:1'b1);
这一行是实现RGB灯工作状态的核心代码,通过(两层)三元运算符在一条表达式内就完成了条件赋值.
这条代码的意思就是,如果标志位flag0
是2'b00
,则R亮度升,若不是,则检测标志为是否为2'b01
,若是,则R亮度降,如不是,则灭.然后通过上一个代码块中的代码可以知道,每一个PWM周期完成后(表现为R已到达最亮或者最暗),状态发生转移,标志为变为下一个状态,R也就在完成了亮度升之后立刻开始亮度降,宏观表现为"呼吸"的状态.
代码整合
上文里两个代码块就足以让一个灯完成一个状态的工作,这部分代码如下
reg[1:0]flag0=2'b00;
always@(posedge STT0)
if(flag0==2'b10)
flag0<=1'b0;
else
flag0<=flag0+1'b1;
assign LED[0]=(flag0==2'b00)?UP:((flag0==2'b01)?DW:1'b1);
reg[1:0]flag1=2'b01;
always@(posedge STT0)
if(flag1==2'b10)
flag1<=1'b0;
else
flag1<=flag1+1'b1;
assign LED[1]=(flag1==2'b00)?UP:((flag1==2'b01)?DW:1'b1);
reg[1:0]flag2=2'b10;
always@(posedge STT0)
if(flag2==2'b10)
flag2<=1'b0;
else
flag2<=flag2+1'b1;
assign LED[2]=(flag2==2'b00)?UP:((flag2==2'b01)?DW:1'b1);
三个灯就相当于将这一段代码例化三次,就可以让三色灯分别进行互相不影响的状态转移(呼吸变化),但是我们的目的是让他们按照文首图中的规律重叠呼吸,该怎么实现呢?
这很简单,很容易想到,三段一样的代码里都分别有一个独立的标志为flag
,他是reg
类型数据,所以可以在定义时给他分配一个初始状态,这样就相当于给三个灯设置了不同的初相,在后面工作的时候由于工作周期相同,就会一直保持最开始的相位差,周期性的进行文首图中的交替呼吸.
至此,彩虹呼吸灯已经完成.
效果
最后的效果图点此查看,图片较大,加载可能比较慢.(因为灯实在是太亮了,就蒙了一层纸来观察颜色变化)
后话
这篇文章是目前写过的第二费力的了,其中的代码更新了很多很多次,在琢磨更精简更巧妙的算法上和修Bug上花了很多的时间和精力,前前后后烧录上板测试不下50次(不夸张T_T),在本地commit了无数个版本,回滚了无数次,一遍一遍修改,最后才得到了你看到的这些代码.我的水平有限,所以就算如此文中的代码和讲解一定有所缺漏,还请希望大家多多包涵,并指出不足之处,改进这篇文章,来帮助更多的人.
本项目完整代码存放在我的Github中,最新版以Github上为准(顺路给颗Star呗;-)
[FPGA]Verilog利用PWM调制巧妙完成RGB三色彩虹呼吸灯(给简约的题目以美妙的解答)的更多相关文章
- 如何使用MATLAB对图片的RGB三种颜色进行提取
参考: https://jingyan.baidu.com/article/456c463b41de5f0a5831448e.html matlab在图像处理方面,具有很强大的应用.下面将分享如何使用 ...
- 利用PWM脉宽调制实现呼吸灯
1.设计目标 完成一个呼吸灯,从亮到灭的时间为2秒,从灭到亮的时间为2秒,以此不断往复. 2.设计步骤 2.1设计分析 利用PWM(脉冲宽度调制)实现led灯亮度的变化,只需要改变占空比就可以实现,具 ...
- [FPGA]Verilog 60s秒表计时器(最大可计时间长达9min)
[FPGA]Verilog 60s秒表计时器 1.引述 这次的实验来自于本人本科课程数电结课时的自选题目.由于这次上传是后知后觉,学校已将小脚丫板子回收,所以在这篇文章中没法贴出代码结果的效果图了,但 ...
- FPGA Verilog HDL 系列实例--------步进电机驱动控制
[连载] FPGA Verilog HDL 系列实例 Verilog HDL 之 步进电机驱动控制 步进电机的用途还是非常广泛的,目前打印机,绘图仪,机器人等等设备都以步进电机为动力核心.那么,下面我 ...
- 单片机PWM调制技术
我们可以看看下图,下图就是一个典型的PWM的波形图. T是一个周期,T1就是高电平所占用的时间,T2就是低电平所占用的时间. 如上图所示T1为脉冲宽度(就是导通时间),周期为T,则输出电压的平均值为U ...
- (原创)用Verilog实现一个参数化的呼吸灯(Verilog,CPLD/FPGA)
1.Abstract 观察到一个有趣的现象,每当把Apple笔记本合上的时候,那个白色的呼吸灯就会反复地由暗渐明,然后又由明渐暗,乍一看就像Apple笔记本在打盹休息一样,十分可爱!于是突发奇 ...
- 小小知识点(三十八)MPSK和MQAM调制的实现——利用IQ调制
IQ调制的原理 (一)调制基本原理 (二)调制基本原理 利用IQ调制实现MPSK(QPSK 8PSK BPSK)和MQAM(16QAM 64QAM)调制 (一)利用IQ调制实现QPSK调制 ...
- ZYNQ自定义AXI总线IP应用——PWM实现呼吸灯效果
一.前言 在实时性要求较高的场合中,CPU软件执行的方式显然不能满足需求,这时需要硬件逻辑实现部分功能.要想使自定义IP核被CPU访问,就必须带有总线接口.ZYNQ采用AXI BUS实现PS和PL之间 ...
- PWM(脉宽调制)——LED特效呼吸灯设计
简述PWM PWM--脉宽调制信号(Pulse Width Modulation),它利用微处理器的数字输出来实现,是对模拟电路控制的一种非常有效的技术,广泛应用于测量.通信.功率控制与变化等许多领域 ...
随机推荐
- OptimalSolution(1)--递归和动态规划(3)数组和字符串问题
一.最长递增子序列(LIS) 给定数组arr,返回arr的最长递增子序列.例如,arr={2,1,5,3,6,4,8,9,7},返回的最长递增子序列为{1,3,4,5,8,9} 1.时间复杂度为O(N ...
- Flask解析(二):Flask-Sqlalchemy与多线程、多进程
Sqlalchemy flask-sqlalchemy的session是线程安全的,但在多进程环境下,要确保派生子进程时,父进程不存在任何的数据库连接,可以通过调用db.get_engine(app= ...
- 第二篇 Flask的Response三剑客及两个小儿子
一.Response三剑客 (一)Flask中的HTTPResponse @app.route("/") #app中的route装饰器 def index(): #视图函数 ret ...
- IntelliJ IDEA 配置Maven仓库
1. 下载Maven 官方地址:http://maven.apache.org/download.cgi 2. 修改本地仓库路径 3. 设置环境变量 MAVEN_HOME: E:\DevelopEnv ...
- (八十六)c#Winform自定义控件-表格优化
出处:http://www.hzhcontrols.com/原文:http://www.hzhcontrols.com/blog-149.html本文版权归www.hzhcontrols.com所有欢 ...
- Java8系列 (七) CompletableFuture异步编程
概述 Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用 get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务 ...
- Excel的IYQ钓鱼
0x00 环境准备 1.操作系统:windows7 2.microsoft office版本:office 2010 0x01 了解IYQ的基本概念 可以将IYQ简单的理解成内置在excel中的一种特 ...
- Mysql常用数据类型归纳总结1
一直在用Mysql数据库,Mysql的数据类型也最常打交道的.但关于Mysql的一些常用数据类型了解程度仅限于一知半解,仅仅能满足满足于平时一些最简单的操作.而Mysql常用数据类型的定义以及规范理解 ...
- js中 对象名.属性名和对象名['属性名']的区别,.和[]的区别
对象中的对象名[ ' 属性名 ' ] 和 对象名.属性名的区别 话不多少,上图分析,菜鸟刚学几个月,如有错误,欢迎大佬们指出 这里是很显而易见的! 然后我们用for in 对他进行遍历,他的区别就出来 ...
- 「动态规划」-数位dp专题
数位dp,今天学长讲的稍玄学,课下花了一会时间仔细看了一下,发现板子是挺好理解的,就在这里写一些: 数位dp主要就是搞一些在区间中,区间内的数满足题目中的条件的数的个数的一类题,题目一般都好理解,这时 ...