欢迎访问博客,Kevin希望通过博客记录下自己在学习FPGA过程中的点点滴滴,使其成为自己一段美好的回忆。^_^点击这里给我发消息

“流水灯”升级,基于FPGA的呼吸灯设计

FPGA学习笔记 Kevin 7763℃ 0评论

算一下,在上海至芯学习已经有半个月了,虽然时间只有半个月,但学到的东西还是挺多的,第一周主要是学习verilog语法和FPGA的开发流程,第二周,也就是现在这周,就开始设计计算器。虽然学习的任务比较重,但过的还是挺充实的,早上8:30左右起来,到晚上10:30之后才回去睡觉。闲话就说到这吧,说多了就有打广告的嫌疑了。

咱们言归正传,用FPGA设计流水灯,相信很多FPGA的初学者都做过这样的一个实验,就像当初学单片机一样,把流水灯做出来后那种成就感油然而生。当然用FPGA做过流水灯实验的朋友现在回过头想,其实流水灯这个实验还是比较简单的,主要就是用到了分频和移位两个思想。所以呢,在我们这一期班上,很多基础好的同学,很快的就把这个实验完成了。当然,可能是咱们这边的老师想多“虐一下”我们,让我们自己做完流水灯后用FPGA做一个呼吸灯。

对于呼吸灯,可能有些朋友不太了解呼吸灯是什么,其实咱们使用的智能手机(比如小米手机)返回桌面的触摸键下方的那个灯,就是一个呼吸灯。呼吸灯显示的一个效果是,灯从灭缓慢的变亮,然后从亮缓慢的变暗,如此循环。

在刚开始设计呼吸灯的时候,可能大家想通过LED灯两端的电压,使电压从零逐渐的增加来实现从灭变亮的这个过程,然后再将电压逐渐降低到零来实现从亮到灭。但是咱们必须要明白一个事实,FPGA引脚输出的电压只有“0”和“1”之分,我们是不能使FPGA的引脚输出电压慢慢增加的。所以通过控制LED灯两端的电压来实现呼吸灯是达不到效果的。

虽然咱们不能使FPGA引脚输出电压从逐渐增加或减小,但是我们可以控制其输出高低电平的时间,若要控制呼吸灯从灭到亮的过程,我们可以使呼吸灯在单位时间内亮的时间依次增加,这样就可以形成这种逐渐变亮的效果。

123

下面咱们说下这个设计的硬件环境以及具体要求:1.系统时钟为25MHz, 2.从灭到亮和从亮到灭的时间均为2S。

要求和基本原理都已经知道了,下面就可以来开始我们的设计。

既然要求我们从灭到亮的时间是2S,我们就可以把这2S分成1000段,然后在这个1000段里边,依次让灯亮的时间增加。又因为我们的灯亮时间是依次递增的,所以我们可以使在后一个2/1000s的灯亮时间与前一个2/1000s的灯亮时间增加2/1000s的1/1000,也就是依次增加2us.即在第一个2/1000s中亮0s,第二个2/1000s中亮2us,第三个2/1000s亮4us,依次递增,第1000个2/1000s亮999x2us。这是我们从灭到亮的一个过程,从亮到灭就是一个逆过程。

根据上边的分析知道,我们的设计中至少需要3个计数器,一个2us计数,一个2ms(2/1000s)计数,一个2s计数。

我们可以先画一下我们这个设计中的理想波形,根据波形来写代码。说到画波形,这是给我们上基础课的亮哥经常强调的一个步骤。因为我们的波形出来了,根据波形来写代码是不需要很多时间的。呼吸灯原理波形图

 

我们来说一下图中变量具体的含义:1.div_cnt是2us计数器,因为我们的系统时钟周期为40ns,所以只需要计50次;2.div_flag是2us计满的标志信号;3.cnt1是2ms(2/1000s)计数,当div_cnt计满2us,也就是50次,div_cnt自加到49的时候cnt1自增1,用来控制我们在某个2/1000s的时间里亮多长时间;4.cnt2可以算是一个2s的计数器,当cnt1计到999时自加1,当cnt2计满到999时,便会又从零开始计数;5.flag是LED灯亮的标志,当flag为高是,灯亮,为低时灯灭。

波形现在说的也很清楚了,下面开始写代码,计数器的定义相对来讲还是非常简单的,什么时候计满归零一眼就能看出来,但是这里我们需要注意cnt2,可能很多朋友对于cnt2的定义会是让cnt2计满到999时马上归零,这是我们很常见的套路,但是大家注意看我们的波形,cnt2并不是计到999就马上归零的,而是需要等cnt1计到999且div_cnt计到49才归零的,不然我们的cnt2为999的时间只有一个时钟周期,这是不符合我们的设计的。下面我们看下正确定义cnt2的代码:cnt2_verilog

cnt2定义好了,那我们的flag怎么定义呢?可能大家看到上边的波形图觉得写代码还是比较简单的,但是我们怎么来定义flag,这确实需要思考一下。我们是需要让flag为高电平的时间依次增加。当然我们在上边的波形图中只是简单的画了一些,画的也不是很规范,可能大家不能马上看出来,对于flag,我们这样定义:当cnt1<cnt2时,flag为高电平,否则为低电平,这样的话,我们就可以利用这些变量来相互制约了。当然这个方法,是上课的老师告诉我们的。得知这个方法后,着实有点佩服这边的老师,智商太高了。

上边的波形只是我们从灭到亮的一个过程,从亮到灭只是一个逆过程而已,逆过程,我们怎么来定义flag呢?通过上边的思路,应该还是不能想到,从亮到灭,我们只需要在cnt1>cnt2时让flag为高电平就可以了。这里的话,我们就还需要定义一个标志,用来控制flag为高是根据cnt1>cnt2还是cnt1<cnt2 。在这里,Kevin是定义把这个标志定义为flag_2s,就是每到2s就翻转一次。flag_2s为低时,就是从灭到亮的过程,cnt1>cnt2,flag为高。

flag_2s定义的代码

接下来,我们看下仿真波形:

呼吸灯仿真波形

大家可以看出来,flag在下一个高电平的时间是要比前一个高电平的时间长的,为了便于仿真,Kevin把仿真的数据改小了,所大家看到波形中的数据,高电平的时间只是依次增加了10ns。

代码下载:链接:http://pan.baidu.com/s/1skjpLzJ 密码:s5x1

转载请注明:邓堪文博客 » “流水灯”升级,基于FPGA的呼吸灯设计

喜欢 (28)or分享 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 看了博客的呼吸灯设计,觉得博主的理论和实现的不一致。博主理论上想要实现的呼吸灯的效果是依次亮2的倍数us,如第一次亮0us第二次亮2us,第三次亮4us即第n次亮2的(n-1)次方us,但是博主使用的cnt1与cnt2进行比较,来决定灯的亮的时间,很明显灯的亮的时间会变成1us、2us、3us.......结果与理论不符
    vegetablebirds2017-05-22 20:41 回复
  2. 不对,是我的理解有问题
    vegetablebirds2017-05-22 20:43 回复