键盘扫描及计算器VHDL仿真.docx
- 文档编号:10868171
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:27
- 大小:118KB
键盘扫描及计算器VHDL仿真.docx
《键盘扫描及计算器VHDL仿真.docx》由会员分享,可在线阅读,更多相关《键盘扫描及计算器VHDL仿真.docx(27页珍藏版)》请在冰豆网上搜索。
键盘扫描及计算器VHDL仿真
简易计算器设计
——EDA实验报告
一、实验内容
实验要求:
完成个位数的加减乘运算,输入用矩阵键盘,输出用数码管显示,每输入一次数据要显示在数码管上。
矩阵键盘共16个按键,用其中10个做个位数的输入,用3个分别做加减乘运算,用其中1个做等于操作,各位数的运算结果最多两位,用动态扫描数码管显示运算结果。
二、小组成员
三、实现方法
系统组成及连接原理如图所示,主要由由七个功能模块组成:
分频模块(为键盘扫描模块和防抖模块提供时钟)、键盘扫描驱动模块(依次置零)、键盘按键值编码模块、键盘编码值防抖模块、运算模块,数码管显示驱动模块、动态扫描驱动模块。
1.分频模块
由于FPGA实验板的原始时钟频率高达33.8688MHz,所以不能直接接入设计模块中使用,就需要用到分频模块。
将33.8688MHz分频到4KHz和10Hz来使用,一个用于行驱动扫描时钟,一个用于防抖模块。
所以,采用写一个可变分频元件来调用。
元件视图:
主要代码如下(完整代码见附录,下同):
architectureRTLoffreq_divisionis
componentfredivnis
generic(n:
positive);
Port(clkin:
inSTD_LOGIC;
clkout:
outSTD_LOGIC);
endcomponent;
begin
U1:
fredivn
genericmap(n=>3)
portmap(clkin=>clk,clkout=>clkout_kb);
endRTL;
仿真结果如下图:
达到预期的目的
2.行驱动模块(依次对行置零):
键盘扫描的原理就是检测行列信号然后判断出具体是按下了哪一个按键。
所以,对行依次置零,当置零频率较快时,按下某一个按键后,一定能得到某一列的信号输出为零,如下图:
当行信号为1110时,若按下了0键,就会得到1110的列信号,立马就快可以译码出按键值,若按下4键、8键、C键则都不会有输出。
主要代码如下:
process(clkin)
begin
ifclr='1'thencount<="00";
elsifrising_edge(clkin)then
ifcount="11"thencount<="00";
elsecount<=count+1;
endif;
endif;
endprocess;
process(count)
begin
ifcount="01"thenkeydrv<="1110";
elsifcount="10"thenkeydrv<="1101";
elsifcount="11"thenkeydrv<="1011";
elsifcount="00"thenkeydrv<="0111";
endif;
endprocess;
仿真结果如下图:
达到预期的目的
3.键值编码模块
依据行驱动模块,当按下某一个按键后,立马可以根据行列和并位信号得到唯一的键盘编码值,用5位矢量来保存结果,当没有按键按下时,编码值一直保持着‘11111’不变,并在后端的模块中不对其做任何处理。
以下列出部分编码表(完整编码表见附录):
十进制数
行&列
HEX
七段码
HEX
0
EE
7E
4
DE
33
5
DD
5B
主要代码如下:
process(clk)
begin
ifclr='0'then
ifrising_edge(clk)then
iftemp1="11101110"then
keyvalue1<="00000";--0
elsiftemp1="11101101"then
keyvalue1<="00001";--1
elsiftemp1="11101011"then
keyvalue1<="00010";--2
elsiftemp1="11100111"then
keyvalue1<="00011";--3
elsiftemp1="11011110"then
keyvalue1<="00100";--4
elsiftemp1="11011101"then
keyvalue1<="00101";--5
elsiftemp1="11011011"then
keyvalue1<="00110";--6
elsiftemp1="11010111"then
keyvalue1<="00111";--7
elsiftemp1="10111110"then
keyvalue1<="01000";--8
elsiftemp1="10111101"then
keyvalue1<="01001";--9
elsiftemp1="10111011"then
keyvalue1<="01010";--10
elsiftemp1="10110111"then
keyvalue1<="01011";--11
elsiftemp1="01111110"then
keyvalue1<="01100";--12
elsiftemp1="01111101"then
keyvalue1<="01101";--13
elsiftemp1="01111011"then
keyvalue1<="01110";--14
elsiftemp1="01110111"then
keyvalue1<="01111";--15
endif;
endif;
endif;
endprocess;
波形仿真如下图:
4.防抖模块
键盘按键物理模型如下:
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上稳定地接通,在断开时也不会一下子断开。
因而在闭合及断开的瞬间均伴随有一连串的抖动,为了不产生这种现象而作的措施就是按键消抖。
抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。
一般来说,软件消抖的方法是不断检测按键值,直到按键值稳定。
实现方法:
假设未按键时输入1,按键后输入为0,抖动时不定。
可以做以下检测:
检测到按键输入为0之后,延时5ms~10ms,再次检测,如果按键还为0,那么就认为有按键输入。
延时的5ms~10ms恰好避开了抖动期。
本模块是采用多次采样来达到防抖的,只有在给定的采样次数内,都保证采样结果一致时才会输出按键编码值。
主要代码如下:
casecountis
when"0000"=>test1<=temp;
when"0001"=>test2<=temp;
when"0010"=>test3<=temp;
when"0011"=>test4<=temp;
when"0100"=>test5<=temp;
when"0101"=>test6<=temp;
when"0110"=>test7<=temp;
when"0111"=>test8<=temp;
when"1000"=>test9<=temp;
when"1001"=>test10<=temp;
when"1010"=>test11<=temp;
when"1011"=>test12<=temp;
when"1100"=>test13<=temp;
when"1101"=>test14<=temp;
when"1110"=>test15<=temp;
when"1111"=>test16<=temp;
whenothers=>null;
endcase;
iftest1=test5andtest2=test6andtest3=test7andtest4=test8andtest5=test9andtest6=test10andtest7=test11andtest8=test12andtest9=test13andtest10=test14andtest11=test15andtest12=test16andtest1/="UUUUUUUU"then
仿真波形如下:
从图中可以看出最终temp1从临时信号temp得到最终输出,达到防抖:
5.运算模块
当前段的模块经过防抖处理以后得到稳定的按键信号,比如1+2=3,转化为编码值就是1011111100111=>EDBBEB7DE7(具体编码表见附录)
主要代码如下:
ifysfh=0thenresult<=first+second;
elsifysfh=1thenresult<=first-second;
elsifysfh=2thenresult<=first*second;
endif;n<=n+'1';
elsifn="100"then
n<="000";
endif;
endif;
endprocess;
process(n)
begin
ifn="001"thenkeyvaluein<=conv_std_logic_vector(first,8);
elsifn="011"thenkeyvaluein<=conv_std_logic_vector(second,8);
elsifn="100"thenkeyvaluein<=conv_std_logic_vector(result,8);
endif;
endprocess;
仿真波形如下:
以1+3=4和5x6=30为例:
编码:
01+03=0405X06=1E
6.数码管显示模块以及动态扫描模块
由于次两个模块是密切相关的,所以统一到一起验证。
经过运算得到最终的显示结果后,要在七段数码管中显示,就必须有每一个数的七段码,同时,由于前面的运算模块的结果最大可以达到81,也就是需要8位二进制,两位十进制来表示,所以就必须通过显示模块来分离出十位和个位。
分离出十位和个位以后,就必须要利用动态扫描使两个数都能显示出来。
因为8个七段数码管的abcdefg位是连在一起的,只有利用分时间隔来显示,一次使能一个数码管,显示一位数,当频率较高时,就可以得到两位数的显示效果。
数码管显示模块主要代码如下:
ifnum=0then
ten:
=0;one:
=10;
elsifnum<10andnum>0then
ten:
=0;one:
=num;
elsifnum<20andnum>9then
ten:
=1;one:
=num-10;
elsifnum<30andnum>19then
ten:
=2;one:
=num-20;
elsifnum<40andnum>29then
ten:
=3;one:
=num-30;
elsifnum<50andnum>39then
ten:
=4;one:
=num-40;
elsifnum<60andnum>49then
ten:
=5;one:
=num-50;
elsifnum<70andnum>59then
ten:
=6;one:
=num-60;
elsifnum<80andnum>69then
ten:
=7;one:
=num-70;
elsifnum<90andnum>79then
ten:
=8;one:
=num-80;
elsifnum<100andnum>89then
ten:
=9;one:
=num-90;
endif;
t<=conv_std_logic_vector(ten,4);
o<=conv_std_logic_vector(one,4);
动态扫描模块主要代码如下:
ifcount="00"then
showout<=show1;en<="00000010";
elsifcount="01"then
showout<=show2;en<="00000001";
endif;
仿真波形如下:
数码显示模块
Show1是十位数,show2是个位数,分别为7E(七段码十六进制)和30,即01。
扫描显示模块
数码管使能信号en依次在01和02中变化,翻译成八段码就是00000001和00000010
四、模块调用
将上述模块按照层次调用,就可以得到最顶层的文件,完成计算器的所有要求功能。
调用图如下:
最终的仿真波形如下:
01=>showout011000030
02=>showout11011016D
03=>showout111100179
由以上波形可以看出:
01+02=03的计算完成了。
五、总结
本次EDA设计实践,完成了从VHDL代码编写到硬件实现的整个流程,掌握了一些FPGA的相关概念以及ISE软件和Active-HDL软件的使用方法。
最重要的就是组员之间的合作,因为VHDL程序是模块化编写的,所以不同模块是由不同人来完成编译的,要达到各个模块之间能够良好的衔接通信,就必须有一个很好的沟通交流,把大家的思路集中起来,一起讨论、编写、调试程序。
【附录一】
完整程序:
分频:
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entityfredivnis
generic(n:
integer:
=3);
Port(clkin:
inSTD_LOGIC;
clkout:
outSTD_LOGIC);
endfredivn;
architectureBehavioraloffredivnis
signalclk1:
std_logic:
='0';
signalcounter:
integerrange0ton;
begin
process(clkin)
begin
ifrising_edge(clkin)then
ifcounter=(n-1)/2then
clk1<=notclk1;
counter<=0;
else
counter<=counter+1;
endif;
endif;
endprocess;
clkout<=clk1;
endBehavioral;
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entitykeyscanis
Port(clr:
instd_logic;
clkin:
inSTD_LOGIC;
keydrv:
outSTD_LOGIC_VECTOR(3downto0));
endkeyscan;
architecturebehavioralofkeyscanis
signalcount:
std_logic_vector(1downto0);
begin
process(clkin)
begin
ifclr='1'thencount<="00";
elsifrising_edge(clkin)then
ifcount="11"then
count<="00";elsecount<=count+1;
endif;
endif;
endprocess;
process(count)
begin
ifcount="01"then
keydrv<="1110";
elsifcount="10"then
keydrv<="1101";
elsifcount="11"then
keydrv<="1011";
elsifcount="00"then
keydrv<="0111";
endif;
endprocess;
endbehavioral;
键值编码:
libraryIEEE;
useIEEE.STD_LOGIC_1164.ALL;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
entitykeydecoderis
Port(clkin,clk,clr:
instd_logic;
keyin:
inSTD_LOGIC_VECTOR(3downto0);
keycode:
outSTD_LOGIC_VECTOR(4downto0)
);
endkeydecoder;
architectureRtlofkeydecoderis
signaltemp:
STD_LOGIC_VECTOR(7downto0);
signalkeydrv1:
STD_LOGIC_VECTOR(3downto0);
signalkeyvalue1:
STD_LOGIC_VECTOR(4downto0);
signaltemp1:
STD_LOGIC_VECTOR(7downto0);
componentkeyscan
Port(clkin,clr:
inSTD_LOGIC;
keydrv:
outSTD_LOGIC_VECTOR(3downto0));
endcomponent;
componentfandou1
Port(clkin,clr:
inSTD_LOGIC;
temp:
instd_logic_vector(7downto0);
temp1:
outSTD_LOGIC_VECTOR(7downto0));endcomponent;
begin
u1:
keyscan
portmap(clkin=>clkin,keydrv=>keydrv1,clr=>clr);
temp<=keydrv1&keyin;
u2:
fandou1
portmap(clkin=>clkin,temp=>temp,
temp1=>temp1,clr=>clr);
process(clk)
begin
ifclr='0'then
ifrising_edge(clk)then
iftemp1="11101110"thenkeyvalue1<="00000";elsiftemp1="11101101"then
keyvalue1<="00001";
elsiftemp1="11101011"thenkeyvalue1<="00010";
elsiftemp1="11100111"thenkeyvalue1<="00011";
elsiftemp1="11011110"thenkeyvalue1<="00100";
elsiftemp1="11011101"thenkeyvalue1<="00101";
elsiftemp1="11011011"thenkeyvalue1<="00110";
elsiftemp1="11010111"thenkeyvalue1<="00111";
elsiftemp1="10111110"thenkeyvalue1<="01000";
elsiftemp1="10111101"thenkeyvalue1<="01001";
elsiftemp1="10111011"thenkeyvalue1<="01010";elsiftemp1="10110111"thenkeyvalue1<="01011";
elsiftemp1="01111110"thenkeyvalue1<="01100";
elsiftemp1="01111101"thenkeyvalue1<="01101";
elsiftemp1="01111011"thenkeyvalue1<="01110";
elsiftemp1="01110111"thenkeyvalue1<="01111";
endif;
endif;
endif;
endprocess;
keycode<=keyvalue1;
endrtl;
防抖:
libraryIEEE;
useIEEE.STD_LOGIC_1164.all;
useIEEE.STD_LOGIC_ARITH.ALL;
useIEEE.STD_LOGIC_UNSIGNED.ALL;
useieee.numeric_std.all;
entityfangdouis
port(keycode:
instd_logic_vector(4downto0);
keycode1:
outstd_logic_vector(4downto0);
start:
outstd_logic;
clk_f,clr:
instd_logic);
endfangdou;
architecturefangdouoffangdouis
signalcount1:
std_logic_vector(2downto0);
signalkey1:
std_logic_vector(4downto0);
signalkey2:
std_logic_ve
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 键盘 扫描 计算器 VHDL 仿真