基于VHDL的键盘扫描及显示电路Word文件下载.docx
《基于VHDL的键盘扫描及显示电路Word文件下载.docx》由会员分享,可在线阅读,更多相关《基于VHDL的键盘扫描及显示电路Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
0]
in
矩阵键盘的扫描输出端口
START
out
数据输出标志
DISPDATA[6..0]
数码管译码显示译码输出
7bit
DASPSEL[1..0]
数码管扫描输出
2bit
CLK_1K
CLK_40K
二、设计思路:
1.循环输出行信号,检测列信号输入,将行列信号相并。
2.译键值。
3.去抖动。
在译没一个键值后,为了防止抖动,加了一个计算环节,一旦检测到列信号后,译码,紧跟着进入计数环节,此时键抖动不会进入其他环节,这样可以防止抖动。
4.数码管译码、循环显示。
电路的具体功能罗列如下:
1)采用4×
4矩阵键盘作为操作数和操作符的输入设备。
2)采用2位8段数码管作为输出显示设备,显示按下的数字及简单的功能。
3)由于所有键盘在按下或者弹起的时候均有按键抖动,所以应该采用去抖电路,当检测到有按键按下去的时候,应该延时20ms后,再进行检测,如果仍有键盘按键被按下去的话,则进行键盘读值。
矩阵键盘模块key_4_4的RTL电路图如下所示。
当CLK_1K上升沿到来时状态转为state0,然后判断列与非后的值,看是否有按键按下,如果有输入数据,则自动启动20ms的计数器,当计满数后,产生一个指示信号,此信号为1bit,高电平有效。
当读到此指示信号后,便再次将row信号锁存至寄存器,便得到键盘的一个返回值。
如果row没有变化,则state转换为state2,对第二行进行按键扫描。
依此类推,扫描第三行与第四行。
因为普通的按键都是接触式的,当按键闭合或释放时,上下接触面都会产生一个很短暂的抖动,如图2.2所示,这个抖动时间一般都会持续5-10ms,虽然这个抖动时间很短,但对于FPGA工作在50M的高频率上的器件来说,还是可以捕捉的到的。
为了使CPU对于一次按键操作只处理一次,在软件中必须加入去除抖动处理。
图2.2按键闭合时产生的抖动
由图中可以看出,最简单的去抖方法就是每隔一段时间读一次键盘,时间间隔大于10ms即可。
如果连续两次检测都有按键被按下,则可以肯定有按键被按下,而且也进入闭合稳定期。
三、数码管显示译码模块设计
数码管显示译码电路主要用来对实际的二进制数据装换为8段数码管的实际显示控制码,采用两个2位的8段共阴极数码管,数码管的显示方式有两种:
静态显示和动态显示。
具体如下:
静态显示方式:
所谓静态显示就是指无论是多少位数码管,同时处于显示状态。
静态显示的优点是:
数码管显示无闪烁,亮度高,软件控制比较容易;
缺点是:
需要的硬件电路较多(每一个数码管都需要一个锁存器),将造成很大的不便,同时由于所有数码管都处于被点亮状态,所以需要的电流很大,当数码管的数量增多时,对电源的要求也就随之增高。
所以,在大部分的硬件电路设计中,很少采用静态显示方式。
动态显示方式:
所谓动态显示,是指无论在任何时刻只有一个数码管处于显示状态,每个数码管轮流显示。
动态显示的优点是:
硬件电路简单(数码管越多,这个优势越明显),由于每个时刻只有一个数码管被点亮,所以所有数码管消耗的电流较小;
数码管亮度不如静态显示时的亮度高,例如有8个数码管,以1秒为单位,每个数码管点亮的时间只有1/8秒,所以亮度较低;
如果刷新率较低,会出现闪烁现象;
如果数码管直接与单片机连接,软件控制上会比较麻烦等。
显示译码方式如下:
1)时钟上升沿到来时分别对位选和段选进行译码。
2)将输入的2bite位选数据译码成4比特数据控制数码管的2位,由于是共阴极数码管要选定相应的数码管则使该位位低电平,其它位为高电平即可,如:
0000译码为0111_1111,对应于实验板上的左边第一位数码管。
3)将输入的4bite段选数据译码为8比特数据控制8个LED的亮灭,最高位接A,最低位接小数点位DP。
若要显示0则对应的译码为8’b1111_1100。
四、仿真
没有键按下时行循环输出“1110”“1101”“1011”“0111”
当随机按下时行保持所按下的状态不变
五、结论
这次EDA课程设计历时十天,学到很多很多的东西。
同时不仅可以巩固以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。
通过这次设计,进一步加深了对EDA的了解,让我对它有了更加浓厚的兴趣。
特别是当每一个子模块编写调试成功时,都会很高兴。
在编写顶层文件的程序时,遇到了不少问题,特别是各元件之间的连接,以及信号的定义,总是有错误。
排除困难后,程序编译就通过了。
在波形仿真时,也遇到了一点困难,想要的结果不能在波形上得到正确的显示,后来,经过屡次的调试之后,才发现在写代码之前对信号的相位考虑不足。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正为社会服务,从而提高自己的实际动手能力和独立思考的能力。
在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
总的来说,这次设计还是比较成功的,在设计中遇到了很多问题,最后在老师的辛勤指导下,终于迎刃而解,有点小小的成就感,终于觉得平时所学的知识有了实用的价值,达到了理论与实际相结合的目的,不仅学到了不少知识,而且锻炼了自己的能力,使自己对以后的路有了更加清楚的认识,同时,对未来有了更多的信心。
最后,对给过我帮助的老师和所有同学再次表示忠心的感!
6、程序
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_ARITH.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITYHHIS
PORT(
CLK_1K:
INSTD_LOGIC;
-- 时钟输入1KHZ
CLK_40K:
--时钟输入40KHZ
KEY_LIE:
INSTD_LOGIC_VECTOR(3DOWNTO0);
--列输入
START:
OUTSTD_LOGIC;
--二-十进制数据输出标志
KEY_HANG:
OUTSTD_LOGIC_VECTOR(3DOWNTO0);
--行输出
DATA_P:
OUTSTD_LOGIC_VECTOR(7DOWNTO0);
--二-十进制数输出
DISP_DATA:
OUTSTD_LOGIC_VECTOR(6DOWNTO0);
--数码管显示译码输出
DISP_SEL:
OUTSTD_LOGIC_VECTOR(1downto0));
--数码管显示扫描输出
END;
ARCHITECTURERTLOFHHIS
SIGNALINT:
STD_LOGIC;
--列与非信号
SIGNALCLK_SEL:
--键值控制1khz的时钟信号
SIGNALSTART_REG:
STD_LOGIC;
--数据输出标志信号
SIGNALDISP_SEL_REG:
STD_LOGIC_VECTOR(1DOWNTO0);
--数码管显示扫描信号
SIGNALDATA_L,DATA_H:
STD_LOGIC_VECTOR(3DOWNTO0);
--二-十进制低位、高位信号
SIGNALDATA_TMP:
--二-十进制低位高位暂存信号
SIGNALKEY_HANG_TMP:
--行输出信号
SIGNALDISP_DATA_REG:
--二-十进制低位、高位暂存信号(数码管用)
SIGNALKEY_CODE:
STD_LOGIC_VECTOR(7DOWNTO0);
--行列相并信号
SIGNALDATA_P_REG:
--二-十进制数信号
BEGIN
KEY_CODE<
=KEY_HANG_TMP&
KEY_LIE;
--行、列相并
DATA_P<
=DATA_P_REG;
START<
=START_REG;
KEY_HANG<
=KEY_HANG_TMP;
DISP_SEL<
=DISP_SEL_REG;
CLK_SEL<
=CLK_1KAND(NOTINT);
--无键按下时有CLK-SEL时钟信号输出
PROCESS(CLK_SEL,CLK_40K,INT)
VARIABLESTATE:
INTEGERRANGE0TO3;
IFRISING_EDGE(CLK_40K)THEN--一个40K的脉冲上升沿到来输入一次列状态以判断是否有按键按下
INT<
=NOT(KEY_LIE(3)ANDKEY_LIE
(2)ANDKEY_LIE
(1)ANDKEY_LIE(0));
ENDIF;
IFRISING_EDGE(CLK_SEL)THEN--一个1K的脉冲的上升沿到来输出一个带表行的状态
CASESTATEIS--变量表示状态机,4循环
WHEN0=>
KEY_HANG_TMP<
="
1110"
;
STATE:
=1;
WHEN1=>
1101"
=2;
WHEN2=>
1011"
=3;
WHEN3=>
0111"
=0;
ENDCASE;
ENDIF;
ENDPROCESS;
PROCESS(CLK_40K,INT)--进程是并行的
INTEGERRANGE0TO3;
VARIABLECOUNTER:
INTEGERRANGE0TO31;
IFINT='
0'
THEN
STATE:
COUNTER:
ELSIFRISING_EDGE(CLK_40K)THEN
CASESTATEIS
WHEN0=>
DATA_TMP<
=DATA_L;
--低四位放入暂存信号
WHEN1=>
--再嵌套一个CASE语句
CASEKEY_CODEIS--实现把像并数据译码十六进制的1到F
WHEN"
01110111"
=>
DATA_L<
0001"
--把1放入低四位
DATA_H<
=DATA_TMP;
--把暂存信号的容放入高四位,相相当于向左移位
=2;
--跳出嵌套CASE语句,转向外CASE语句的状态2
01111011"
0010"
01111101"
0011"
01111110"
0100"
10110111"
0101"
10111011"
0110"
10111101"
10111110"
1000"
11010111"
--9键
1001"
11011011"
--0键
0000"
11011101"
--A键,实现步进加一功能
IFDATA_H="
IFDATA_L="
DATA_H<
DATA_L<
ELSEDATA_L<
=DATA_L+1;
ELSIFDATA_L="
=DATA_H+1;
ELSE
=DATA_L+1;
=DATA_H;
WHEN"
11011110"
--B键,实现步键加十
IFDATA_H="
=DATA_L;
=DATA_H+1;
11100111"
--C键,实现步进减一
ANDDATA_H="
ELSIFDATA_L="
=DATA_H-1;
ELSE
=DATA_L-1;
11101011"
=>
--D键,实现步进减十
=DATA_H-1;
11101110"
--E键,实现送数功能
DATA_P_REG<
=DATA_H&
DATA_L;
START_REG<
='
1'
--数据输出标志信号置一
WHEN"
11101101"
--F键,实现清零功能
WHENOTHERS=>
--不可缺少
ENDCASE;
WHEN2=>
--状态2实现去抖动功能
IFCOUNTER=31THEN--计数延时去抖
=COUNTER+1;
WHEN3=>
--清除数据输出标志
PROCESS(CLK_1K,DATA_L,DATA_H)--数码管循环显示
VARIABLESTATE:
INTEGERRANGE0TO1;
IFRISING_EDGE(CLK_1K)THEN
CASESTATEIS
WHEN0=>
DISP_SEL_REG<
10"
--输入10到数码管显示扫描信号
DISP_DATA_REG<
--二-十进制低高位暂存节点
01"
PROCESS(CLK_1K,DISP_DATA_REG)--数码管译码
CASEDISP_DATA_REGIS
DISP_DATA<
1111110"
--0
0110000"
--1
1101101"
1111001"
0110011"
1011011"
1011111"
1110000"
1111111"
1111011"
0000000"
END;