键盘扫描及计算器VHDL仿真.docx

上传人:b****4 文档编号:4344225 上传时间:2022-11-30 格式:DOCX 页数:27 大小:118.18KB
下载 相关 举报
键盘扫描及计算器VHDL仿真.docx_第1页
第1页 / 共27页
键盘扫描及计算器VHDL仿真.docx_第2页
第2页 / 共27页
键盘扫描及计算器VHDL仿真.docx_第3页
第3页 / 共27页
键盘扫描及计算器VHDL仿真.docx_第4页
第4页 / 共27页
键盘扫描及计算器VHDL仿真.docx_第5页
第5页 / 共27页
点击查看更多>>
下载资源
资源描述

键盘扫描及计算器VHDL仿真.docx

《键盘扫描及计算器VHDL仿真.docx》由会员分享,可在线阅读,更多相关《键盘扫描及计算器VHDL仿真.docx(27页珍藏版)》请在冰豆网上搜索。

键盘扫描及计算器VHDL仿真.docx

键盘扫描及计算器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

11101110

EE

1111110

7E

4

11011110

DE

0110011

33

5

11011101

DD

1011011

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,转化为编码值就是11101101101110110111110111100111=>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);

si

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1