本帖最后由 735953120@qq.co 于 2015-8-17 20:04 编辑
这是昨天刚刚做完的一个,小项目主要是为了练习按键消抖、数码管显示、二进制转bcd码的练习。刚开始学习FPGA,所以没事就总结一下自己的学习过程,如有不对的地方恳请大家指出来,楼主一定改正,互相学习 。项目要求:将按键的次数显示到数码管上面。本项目中的方法是我通过看李凡李老师的授课视频,还有就是自己在实践中遇到的问题,写的。在这给老师赞一个 。
拿到这个小项目的时候,我首先是哪出了笔和纸对,对我要实现的功能进行分析。该项目的总体框图如下:
图中的key_scan模块为按键扫描与消抖模块,count_key模块主要是计数按键次数的模块,bin_BCD模块实现二进制转BCD码,seg模块实现按键次数的显示(本次有6个数码管)。 接下来我首先做的是设计并分析key_scan模块,这个模块使用的按键就是我们常见的机械按键,工业上的是20ms~200ms之间,为按键按下,我的也是采用的是20ms的消抖。当按键按下的时间小于20ms为抖动,大于则表示按键按下,按键抬起的抖动时间也为20ms。接下来我画出了这个模块的状态转移图如下图:
状态转移图中的temp是用来寄存按键状态的寄存器,cunt_n则是一个计数器计数按键按下的时间。接下来我跟据所画的状态图编写代码如下:
接下来就是计数按键按下次数的模块,我是这样做的每当按键的被按下会产生一段的低电平,而我则是采集其松开时会产生一个由低到高跳变的过程,每当这个上升沿到来的时候计数器计一次数,说白了就是用key_out的充当时钟。这个模块比较简单大家就看上面的系统框图中的count_key模块的框图。接下来是这个模块的代码如下:
接下来就是进制转换模块了。说到这个模块的话,我要好好说说了 ,由系统框图我们也可以看出来,这个模块的输入就是计数模块的输出,而计数模块输出的数据是的二进制数,为啥位宽是20,原因是数码管显示的最大数是999999,其对应的二进制数就是二十位的。数码管输入的数据则是BCD码,所以我们在进行数码管显示之前必须先将二进制数转换为BCD码。进制转换我是看李老师的讲的逐步移位法。给大家来个例子说明一下 例如输入的二进制数是8’b1111_1111,经过逐步移位的方法最终得到的BCD码为:12’b1_0101_0101,其对应的十进制百位,十位,个位,分别是:2,5,5.这种移位的方法首先设计者必须清楚的是被转换的二进制数的位宽,和最终转换为BCD码的位宽,由于中间用到一个移位寄存器此移位寄存器的位宽等于被转的二进制数位宽加上最终转换的BCD码的位宽。所以本例中的移位寄存器位宽为20,采用这种方法移位的此处比位修正的次数多一次,即就是最后一次只进行移位操作,而不进行位修正计数(每位所对应的4位BCD码如果大于四必须进行加三操作)。应用这种方法移完即可得到对应的BCD码。本例子的以为过程及修正如下表所示:
通过这个例子大家应该对二进制转BCD有一定的了解,下来进入我们的正题,我输入的是20位的二进制数,6个数码管显示的话要24为BCD码,所以我需要的移位寄存器的位宽为44.整个的转换过程是先进行移位操作最后进行位修正操作。这个模块我将他们独立出来:移位为一个模块bcd_modify,未修正为一个模块bcd_sigle_modify。下面是我的这两个模块的框图:
下面是我这个模块的程序:
接下来设计最后一个模块的设计数码管显示模块的设计。本次设计采用的是共阳极数码管,故当有低电平时对应的数码管的段会点亮。数码管分位选和片选,位选顾名思义就是控制那个数码管进行显示,而片选则是存有显示数据。数码管显示部分,我采用的是1khz的时钟,如果时钟过快,数码管会显示常亮状态。数码管显示的数据要进行数码管译码操作。故可以总结为:此模块要做分频,位选的控制,还有数据的译码这几部分。我用的是以前做数码管显示是的一个现成的程序,所以这部分的程序是在一个模块下写的,程序如下:
接下来这个是我总体的顶层模块程序:
下来是是我的测试部分的代码:
作者:会飞的小鸟
测试波形图如下 |