EDA设计++键盘驱动程序.docx
《EDA设计++键盘驱动程序.docx》由会员分享,可在线阅读,更多相关《EDA设计++键盘驱动程序.docx(34页珍藏版)》请在冰豆网上搜索。
![EDA设计++键盘驱动程序.docx](https://file1.bdocx.com/fileroot1/2023-1/26/fe084750-aa35-4950-8525-39ed0e079a38/fe084750-aa35-4950-8525-39ed0e079a381.gif)
EDA设计++键盘驱动程序
键盘驱动程序
摘要
键盘上的每一个键都有两个唯一的数值进行标志。
为什么要用两个数值而不是一个数值呢?
这是因为一个键可以被按下,也可以被释放。
当一个键按下时,它们产生一个唯一的数值,当一个键被释放时,它也会产生一个唯一的数值,我们把这些数值都保存在一张表里面,到时候通过查表就可以知道是哪一个键被敲击,并且可以知道它是被按下还是被释放了。
这些数值在系统中被称为键盘扫描码。
本课程设计目的旨在使用Altera公司的EP2C35系列的FPGA芯片,利用SOPC-NIOSII-EP2C35开发板PS2键盘接口等资源,实现一个键盘驱动程序。
以达到外接键盘按键的选择、8位动态七段数码管实现按键扫描码显示和16*16点阵实现按键字符显示的目的。
关键词:
键盘;扫描码;数码管
1绪论
EDA是电子设计自动化(ElectronicDesignAutomation)的缩写,在20世纪60年代中期从计算机辅助设计(CAD)、计算机辅助制造(CAM)、计算机辅助测试(CAT)和计算机辅助工程(CAE)的概念发展而来的。
20世纪90年代,国际上电子和计算机技术较先进的国家,一直在积极探索新的电子电路设计方法,并在设计方法、工具等方面进行了彻底的变革,取得了巨大成功。
在电子技术设计领域,可编程逻辑器件(如CPLD、FPGA)的应用,已得到广泛的普及,这些器件为数字系统的设计带来了极大的灵活性。
这些器件可以通过软件编程而对其硬件结构和工作方式进行重构,从而使得硬件的设计可以如同软件设计那样方便快捷。
这一切极大地改变了传统的数字系统设计方法、设计过程和设计观念,促进了EDA技术的迅速发展。
EDA技术就是以计算机为工具,设计者在EDA软件平台上,用硬件描述语言HDL完成设计文件,然后由计算机自动地完成逻辑编译、化简、分割、综合、优化、布局、布线和仿真,直至对于特定目标芯片的适配编译、逻辑映射和编程下载等工作。
EDA技术的出现,极大地提高了电路设计的效率和可操作性,减轻了设计者的劳动强度。
本课程设计目的旨在使用Altera公司的EP2C35系列的FPGA芯片,利用SOPC-NIOSII-EP2C35开发板PS2键盘接口等资源,实现一个键盘驱动程序。
以达到外接键盘按键的选择、8位动态七段数码管实现按键扫描码显示和16*16点阵实现按键字符显示的目的。
利用EDA工具,电子设计师可以从概念、算法、协议等开始设计电子系统,大量工作可以通过计算机完成,并可以将电子产品从电路设计、性能分析到设计出IC版图或PCB版图的整个过程的计算机上自动处理完成。
2系统设计
VHDL语言是一种用于电路设计的高级语言。
它在80年代的后期出现。
最初是由美国国防部开发出来供美军用来提高设计的可靠性和缩减开发周期的一种使用范围较小的设计语言。
VHDL主要用于描述数字系统的结构,行为,功能和接口。
除了含有许多具有硬件特征的语句外,VHDL的语言形式和描述风格与句法是十分类似于一般的计算机高级语言。
对于用VHDL完成的一个确定的设计,可以利用EDA工具进行逻辑综合和优化,并自动的把VHDL描述设计转变成门级网表。
VHDL的程序结构特点是将一项工程设计,或称设计实体(可以是一个元件,一个电路模块或一个系统)分成外部(或称可视部分,及端口)和内部(或称不可视部分),既涉及实体的内部功能和算法完成部分。
在对一个设计实体定义了外部界面后,一旦其内部开发完成后,其他的设计就可以直接调用这个实体。
这种将设计实体分成内外部分的概念是VHDL系统设计的基本点。
与其他的硬件描述语言相比,VHDL具有更强的行为描述能力,从而决定了它成为系统设计领域最佳的硬件描述语言。
强大的行为描述能力是避开具体的器件结构,从逻辑行为上描述和设计大规模电子系统的重要保证。
本文利用模块化思想将整个设计分为八位七段数码管显示、16*16点阵显示和键盘扫描等模块,以达到键盘扫描码的显示。
2.1总体设计
在本课程设计中要求利用外接键盘实现键盘按键的选择,在8位动态七段数码管上实现按键扫描码的显示,在16*16点阵上实现按键字符的显示。
设计中采用模块化,用键盘扫描输出端作为数据总线来对整个程序控制,各模块共一个系统时钟,数字信号源模块的时钟选择为1MHZPS2键盘采用是键盘内部的时钟。
其总体设计如下图2.1所示。
图2.1系统总体设计
2.2八位七段数码管显示模块
八位七段数码管是电子开发过程中常用的输出显示设备。
在实验系统中使用的是两个四位一体、共阴极型七段数码管。
由于七段数码管公共端连接到GND(共阴极型),当数码管的中的那一个段被输入高电平,则相应的这一段被点亮。
反之则不亮。
共阳极性的数码管与之相么。
四位一体的七段数码管在单个静态数码管的基础上加入了用于选择哪一位数码管的位选信号端口。
八个数码管的a、b、c、d、e、f、g、h、dp都连在了一起,8个数码管分别由各自的位选信号来控制,被选通的数码管显示数据,其余关闭。
其单个静态数码管如下图2.2所示,数码管显示模块的电路原理如图2.3所示。
图2.2静态七段数码管
图2.3数码管显示电路原理
2.316*16点阵显示模块
16*16点阵由此256个LED通过排列组合而形成16行*16列的一个矩阵式的LED阵列,俗称16*16点阵。
单个的LED的电路如下图2.4所示。
图2.4单个LED电路图
由上图可知,对于单个LED的电路图当Rn输入一个高电平,同时Cn输入一个低电平时,电路形成一个回路,LED发光。
也就是LED点阵对应的这个点被点亮。
16*16点阵也就是由16行和16列的LED组成,其中每一行的所有16个LED的Rn端并联在一起,每一列的所有16个LED的Cn端并联在一起。
通过给Rn输入一个高电平,也就相当于给这一列所有LED输入了一个高电平,这时只要某个LED的Cn端输入一个低电平时,对应的LED就会被点亮。
具体的电路如下图2.5所示。
图2.516*16点阵电路原理图
16*16点阵的电路原理在前面已经做了详尽的说明,在此实验中,16*16点阵由4个8*8点阵组成,考虑到LED电流功耗与FPGA电流功耗的关系,在实验的电路中加入驱动电路。
具体电路如下图2.6所示。
图2.616*16点阵电路图
2.4键盘扫描模块
PS2通信协议是一种双向同步串行通迅协议。
通迅的两端通过CLOCK(时钟信号端)同步,并通过DATA(数据端口)交换数据。
任何一方如果想要抑制另外一方的通迅时,只需要把CLOCK拉到低电平。
PS2控制接口仅使用到两条传输端口,一为频率端口,另一则为数据端口如图2.7所示,且此传输埠必为三态(Tri-State)并具有双向(bidirectional)特性。
PS2传输产品上,常见为鼠标与键盘,两者的驱动原理均相同,仅扫描码(scancode)不同。
因此我们以PS2键盘为例进行说明。
Male
(Plug)
Female
(Socket)
6-pinMini-DIN(PS2):
1-Data
2-NotImplemented
3-Ground
4-Vcc(+5V)
5-Clock
6-NotImplemented
图2.7PS2端口脚位定义
键盘其实就是一个大型的按键矩阵,它们由安装在电路板上的处理器(叫做“键盘编码器”)来监视着。
虽然不同的键盘可能采用不同的处理器,但是它们完成的任务都是一样的,即监视哪些按键被按下,哪些按键被释放了,并将这些信息传送到主机。
如果有必要,处理器处理所有的去抖动,并在它的16字节的缓冲区里缓冲数据。
主机端包含了一个“键盘控制器”与键盘处理器进行通讯,并解码来自键盘处理器的信息,然后高速系统当前按键对应的处理事情。
主机与键盘之间的通讯仍旧采用IBM的协议。
键盘处理器花费很多时间来扫描或监视按键矩阵。
如果发现有按键按下、释放或长按,键盘就发送“扫描码”的信息到主机。
扫描码有两种不同的类型:
“通码”和“断码”。
当一个键被按下去或长按的时候,键盘就发送通码;当一个键被释放的时候,键盘就发送断码。
每个键盘被分配了唯一的通码和断码,这样主机通过查找唯一的扫描码就可以确定是哪个按键被按下或释放。
每个键一整套的通断码组成了“扫描码集”,现在所有的键盘都采用第二套扫描码。
由于没有一个简单的公式可以计算扫描码,所以要知道某个特定按键的通码和断码,只能采用查表的方法来获得。
需要特别注意的是,按键的通码值表示键盘上的一个按键,并不表示印刷在按键上的那个字符,这就意味着通码和ASCII码之间没有任何关联。
另外,第二套通码都只有一个字节宽,但也有少数“扩展按键”的通码是两字节或四字节宽,这类码的第一个字节总是0xE0。
与通码一样,每个按键在释放的时候,键盘就会发送一个断码。
每个键也都有它自己的唯一的断码,不过庆幸的是,断码与断码之间存在着必然的联系。
多数第二套断码有两个字长,它们的第一个字节是0xF0,第二个字节就是对应按键的通码。
扩展按键的断码通常有三个字节,前两个字节0xE0和0xF0,最后一个字节是这个按键通码的最后一个字节。
表2-1列出了键盘的扫描码。
键值
通码
断码
键值
通码
断码
键值
通码
断码
A
1C
F0,1C
9
46
F0,46
[
54
F0,54
B
32
F0,32
`
0E
F0,0E
INSERT
67
F0,67
C
21
F0,21
-
4E
F0,4E
HOME
6E
F0,6E
D
23
F0,23
=
55
F0,55
PGUP
6F
F0,6F
E
24
F0,24
\
5C
F0,5C
DELETE
64
F0,64
F
2B
F0,2B
BKSP
66
F0,66
END
65
F0,65
G
34
F0,34
SPACE
29
F0,29
PGDN
6D
F0,6D
H
33
F0,33
TAB
0D
F0,0D
UARROW
63
F0,63
I
43
F0,48
CAPS
14
F0,14
LARROW
61
F0,61
J
3B
F0,3B
LSHFT
12
F0,12
DARROW
60
F0,60
K
42
F0,42
LCTRL
11
F0,11
RARROW
6A
F0,6A
L
4B
F0,4B
LWIN
8B
F0,8B
NUM
76
F0,76
M
3A
F0,3A
LALT
19
F0,19
KP/
4A
F0,4A
N
31
F0,31
RSHFT
59
F0,59
KP*
7E
F0,7E
O
44
F0,44
RCTRL
58
F0,58
KP-
4E
F0,4E
P
4D
F0,4D
RWIN
8C
F0,8C
KP+
7C
F0,7C
Q
15
F0,15
RALT
39
F0,39
KPEN
79
F0,79
R
2D
F0,2D
APPS
8D
F0,8D
KP.
71
F0,71
S
1B
F0,1B
ENTER
5A
F0,5A
KP0
70
F0,70
T
2C
F0,2C
ESC
08
F0,08
KP1
69
F0,69
U
3C
F0,3C
F1
07
F0,07
KP2
72
F0,72
V
2A
F0,2A
F2
0F
F0,0F
KP3
7A
F0,7A
W
1D
F0,1D
F3
17
F0,17
KP4
6B
F0,6B
X
22
F0,22
F4
1F
F0,1F
KP5
73
F0,73
Y
35
F0,35
F5
27
F0,27
KP6
74
F0,74
Z
1A
F0,1A
F6
2F
F0,2F
KP7
6C
F0,6C
0
45
F0,45
F7
37
F0,37
KP8
75
F0,75
1
16
F0,16
F8
3F
F0,3F
KP9
7D
F0,7D
2
1E
F0,1E
F9
47
F0,47
]
5B
F0,5B
3
26
F0,26
F10
4F
F0,4F
;
4C
F0,4C
4
25
F0,25
F11
56
F0,56
'
52
F0,52
5
2E
F0,2E
F12
5E
F0,5E
41
F0,41
6
36
F0,36
PRNT
SCRN
57
F0,57
.
49
F0,49
7
3D
F0,3D
SCROLL
5F
F0,5F
/
4A
F0,4A
8
3E
F0,3E
PAUSE
62
F0,62
表2-1PS2键盘扫描码
2.5动态扫描模块
本次设计所用的实验箱FPGA的引脚都和相应的实验开发模块固化了,并且有些引脚在几个模块里有重复定义。
在EDA中不允许一个引脚同时两个模块使用。
在本设计中,八位七段数码管和16*16点阵的部分管脚被重复定义,若要同时显示,就要用到动态扫描。
当扫描频率达到一定值时,效果就会和静态显示一样。
这样既解决了引脚冲突的问题,又有效的节约了硬件资源。
同时,实验也达到了预期的效果。
3程序设计
3.1流程
键盘扫描程序是整个程序的核心部分,其流程图如下图3.1所示。
图3.1键盘扫描程序流程图
3.2八位七段数码管显示程序
八位七段数码管显示程序,采用动态显示,每个数码管均可以从0到9、A到F的显示。
通过查询键盘输出端的数据总线的通码值,将相应的通码在数码管上显示出来。
程序见附录A,八位七段数码管显示如图3.2所示。
图3.2八位七段数码管
3.316*16点阵显示程序
16*16点阵显示程序,通过查询数据总线的通码值,在LED点阵上显示键盘上相应的符号。
程序见附录B,16*16点阵显示如图3.3所示。
图3.316*16点阵
3.4键盘扫描程序
扫描码有两种不同的类型:
“通码”和“断码”。
当一个键被按下去或长按的时候,键盘就发送通码;当一个键被释放的时候,键盘就发送断码。
每个键盘被分配了唯一的通码和断码,这样主机通过查找唯一的扫描码就可以确定是哪个按键被按下或释放。
程序见附录C。
3.5动态扫描程序
动态扫描程序,控制八位七段数码管和16*16点阵单独显示,当系统时钟频率达到一定值时,显示效果就和静态显示一样了。
程序见附录D。
4总结
4.1遇到的问题及解决
课程设计一开始,老师先让我们熟悉了实验指导书上的实验一到实验六这六个实验,目的旨在于让我们熟悉课程设计的步骤以及相关的软硬件知识。
这六个实验相对来说比较简单,我与同学们基本上实现了仿真,只是我拿到的数据线有问题,实验的先前阶段我又没有发现这问题,所以一直没有实现仿真,后来问了下同学,才知道是数据线的问题,找到了症结所在,接下来的事就水到渠成了。
课程设计不可能不碰到一些问题比如:
硬件的问题,软件的问题,程序的问题。
我们这次课程设计使用的是新的设备,所以基本上没有出现硬件故障,只是有个别同学没有看设备的使用说明书,在做实验时碰到了一些操作问题,像什么数字信号模块的时钟没有选对啊,实验箱的电源没有插好啊等等。
仿真软件也由于我们先前做了六个基本实验,碰到的问题也不到,哦,记起来了,有个问题困扰了我们很多同学,就是把实验箱与电脑连接的时候,发现实验箱与电脑无法正常的进行数据交换,我们很多同学开始都在想是不是实验箱坏了,后来发现是电脑没有找到硬件,经过扫描让电脑找到新的硬件后,问题也随之解决了。
碰到问题最多的是在编程的时候,众所周知,编写程序是项很枯燥无味的事,幸好我们有些例子程序,这样我们也不需要完全把程序编出来,只要编某个模块就行了,这次使用的实验箱上的接口有很多是共用一个端口,这给我们造成了很大的麻烦,要不是老师告诉使用动态扫描的方法,我们也许还不能实现这次课程设计的仿真。
4.2扩展设想
我们可以通过按下外接键盘的按键,使实验箱上除了显示键盘的扫描码外播放音乐的基准音符,也可以通过12位LED灯的点亮数目来记录你按下了多少次按键。
4.3心得与体会
设计之初,我对EDA知识的掌握应该说是还没入门,随着设计的深入,碰到了一系列的问题,为了实现仿真,我们就不得不去解决这一系列的问题,这样在解决问题的过程中我们不知不觉的就对EDA知识有了更深的了解,同时也巩固了以前的知识。
通过编程,我发现VHDL语言跟C语言、汇编语言在某些方面是相通的,所以无形之中我也对计算机语言有了更深的认识。
编程是很费神的,又是一项细致活,这很锻炼人,同时也磨练人的意志。
其实不管做什么,只要你用心认真的去做,你总是会发现很多有用的知识,你也会学到很多。
参考文献
[1]SOPCIIEDA实验指导书(第二版)[M].
[2]SOPCII使用手册(第二版)[M].
[3]谭会生.EDA技术基础[M].湖南大学出版社,2004.
[4]潘松,黄继业.EDA技术实用教程(第二版)[M].科学出版社,2005.
附录
附录A八位七段数码管显示程序
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
useieee.std_logic_unsigned.all;
--------------------------------------------------------------------
entityledis
port(clk:
instd_logic;--ClockSignal
data_in:
instd_logic_vector(7downto0);--databus
ledag:
outstd_logic_vector(6downto0);--定义七位输出信号
sel:
outstd_logic_vector(2downto0)--ledagSelect
);
endled;
--------------------------------------------------------------------
architecturebehaveofledis
signaldcount:
std_logic_vector(2downto0);
signaladh,adl:
std_logic_vector(6downto0);
signaladcount:
std_logic_vector(7downto0);
signaldin_h,din_l:
std_logic_vector(3downto0);
signalcoclk:
std_logic;
begin
process(clk)--outenablesignal
begin
if(clk'eventandclk='1')then
ifadcount="10000000"then
coclk<='1';
adcount<="00000000";
else
adcount<=adcount+1;
coclk<='0';
endif;
endif;
endprocess;
process(clk)--rdtheadcdata
begin
if(clk'eventandclk='1')then
din_h<=data_in(7downto4);
din_l<=data_in(3downto0);
endif;
endprocess;
process(clk)
begin
casedin_his
when"0000"=>adh<="0111111";--display0
when"0001"=>adh<="0000110";--display1
when"0010"=>adh<="1011011";--display2
when"0011"=>adh<="1001111";--display3
when"0100"=>adh<="1100110";--display4
when"0101"=>adh<="1101101";--display5
when"0110"=>adh<="1111101";--display6
when"0111"=>adh<="0000111";--display7
when"1000"=>adh<="1111111";--display8
when"1001"=>adh<="1101111";--display9
when"1010"=>adh<="1110111";--displaya
when"1011"=>adh<="1111100";--displayb
when"1100"=>adh<="0111001";--displayc
when"1101"=>adh<="1011110";--displayd
when"1110"=>adh<="1111001";--displaye
when"1111"=>adh<="1110001";--displayf
whenothers=>adh<=adh;--nochange
endcase;
casedin_lis
when"0000"=>adl<="0111111";--display0
when"0001"=>adl<="0000110";--display1
when"0010"=>adl<="1011011";--display2
when"0011"=>adl<="1001111";--display3
when"0100"=>adl<="1100110";--display4
when"0101"=>adl<="1101101";--display5
when"0110"=>adl<="1111101";--display6
when"0111"=>adl<="0000111";--display7
when"1000"=>adl<="1111111";--display8
when"1001"=>adl<="1101111";--display9
when"1010"=>adl<="1110111";--displaya
when"1011"=>adl<="1111100";--displayb
when"1100"=>adl<="0111001";--displayc
when"1101"=>adl<="1011110";--d