VHDL课程设计PS2键盘.docx
《VHDL课程设计PS2键盘.docx》由会员分享,可在线阅读,更多相关《VHDL课程设计PS2键盘.docx(27页珍藏版)》请在冰豆网上搜索。
VHDL课程设计PS2键盘
VHDL课程设计-PS2键盘
1、课程设计的目的与任务
(1)熟练掌握EDA工具软件QuartusII的使用;
(2)熟练用VHDL硬件描述语言描述数字电路;
(3)学会使用VHDL进行大规模集成电路设计;
(4)学会用CPLD\FPGA使用系统硬件验证电路设计的正确性;
(5)初步掌握EDA技术并具备一定的可编程逻辑芯片的开发能力;
2、课程设计题目
1、指定题目:
0:
多功能计数器;1:
数字秒表;2:
简易数字钟;3:
简易频率计;
4:
彩灯控制器;5:
交通灯控制器;6:
四路智力竞赛抢答器;
7:
简易微波炉控制器;8:
表决器;9:
数字密码锁;
我的的学号尾数是2,所以我要做的题目是简易数字钟。
由于我之前已经学过VerilogHDL和VHDL,所以简易数字钟相对于我比较简单,我完成了简易数字钟并验收后,再选择了另一个自选题目来完成。
简易数字钟:
设计一个以“秒”为基准信号的简易数字钟,显示时、分、秒,同时可实现整点报时和清零(我已经完成,而且已经验收了)。
2、自选题目:
在完成了数字钟的设计后,我选择了另一个设计的题目,那就是PS2键盘扫描。
所以这次课程设计我的报告主要详细写的是PS2键盘扫描的程序,而不是简易数字钟。
PS键盘扫描:
设计一个PS键盘扫描程序,能接受键盘的输入时钟和数据,区别哪一个键输入,同时解译通码和断码,使用LED灯来显示收到的数据。
3、课程设计的内容与要求
1、设计内容
(1)系统功能的分析;
(2)实现系统功能的实际方案;
(3)编写各功能模块的VHDL语言程序;
(4)对各功能模块进行编译、综合、仿真、分析;
(5)顶层文件设计
(6)对整个系统进行编译、综合、仿真、分析;
(7)在CPLD\FPGA实验开发系统试验箱上进行硬件验证;
(8)写实验报告;
2、设计要求
(1)按所布置的题目要求,每一位学生独立完成全过程;
(2)分模块层次化设计;
(3)各功能模块的底层文件必须用VHDL语言设计,顶层文件可用VHDL语言设计,也可以用原理图设计。
4、实验仪器设备
(1)PC机;
(2)QuartusII软件;
(3)黑金FPGA实验开发系统,芯片为CycloneII的EP2C5Q208C8;
5、设计方案
1、PS2解码
图1为PS2的接口图。
我使用的的右边的PS2接口,即1脚为数据脚,5脚为时钟脚,同时我编写的VHDL代码只对1脚和5脚操作。
图2PS2协议时序图
图2为PS2协议时序图。
由图可以解读出,PS2协议对数据的读取时“CLK的下降沿”有效,而数据的放置时在“CLK的上升沿”。
PS2频率比较慢,大概为10KHz。
第N位
属性
0
开始位
1~8
数据位
9
校验位
10
结束位
表1PS2数据说明
PS2的一帧数据时11位。
对PS2进行解码,我们需要得到的是1~8位的数据位。
其他的位,可以使用取巧的方法编写。
键盘的编码有“通码(Make)”和“断码(Break)”之分。
通码相当于某个按键按下了,断码相当于某个按键释放了。
假设,我们按下了“Z”键不放,大约每秒有10个X“1A”的通码(10KHz),而当我们释放“Z”键,就会输出断码X“F0”和X“1A”。
同时,键盘编码一次只能有一个输出,即多个按键同时按下时,只有一个有效。
下表为第二套PC键盘扫描码。
键 名
通 码
断 码
-
键 名
通 码
断 码
-
键 名
通 码
断 码
A
1C
F0,1C
9
46
F0,46
[
54
FO,54
B
32
F0,32
`
0E
F0,0E
INSERT
E0,70
E0,F0,70
C
21
F0,21
-
4E
F0,4E
HOME
E0,6C
E0,F0,6C
D
23
F0,23
=
55
FO,55
PGUP
E0,7D
E0,F0,7D
E
24
F0,24
\
5D
F0,5D
DELETE
E0,71
E0,F0,71
F
2B
F0,2B
BKSP
66
F0,66
END
E0,69
E0,F0,69
G
34
F0,34
SPACE
29
F0,29
PGDN
E0,7A
E0,F0,7A
H
33
F0,33
TAB
0D
F0,0D
UARROW
E0,75
E0,F0,75
I
43
F0,43
CAPS
58
F0,58
LARROW
E0,6B
E0,F0,6B
J
3B
F0,3B
LSHFT
12
FO,12
DARROW
E0,72
E0,F0,72
K
42
F0,42
LCTRL
14
FO,14
RARROW
E0,74
E0,F0,74
L
4B
F0,4B
LGUI
E0,1F
E0,F0,1F
NUM
77
F0,77
M
3A
F0,3A
LALT
11
F0,11
KP/
E0,4A
E0,F0,4A
N
31
F0,31
RSHFT
59
F0,59
KP*
7C
F0,7C
O
44
F0,44
RCTRL
E0,14
E0,F0,14
KP-
7B
F0,7B
P
4D
F0,4D
RGUI
E0,27
E0,F0,27
KP+
79
F0,79
Q
15
F0,15
RALT
E0,11
E0,F0,11
KPEN
E0,5A
E0,F0,5A
R
2D
F0,2D
APPS
E0,2F
E0,F0,2F
KP.
71
F0,71
S
1B
F0,1B
ENTER
5A
F0,5A
KP0
70
F0,70
T
2C
F0,2C
ESC
76
F0,76
KP1
69
F0,69
U
3C
F0,3C
F1
05
F0,05
KP2
72
F0,72
V
2A
F0,2A
F2
06
F0,06
KP3
7A
F0,7A
W
1D
F0,1D
F3
04
F0,04
KP4
6B
F0,6B
X
22
F0,22
F4
0C
F0,0C
KP5
73
F0,73
Y
35
F0,35
F5
03
F0,03
KP6
74
F0,74
Z
1A
F0,1A
F6
0B
F0,0B
KP7
6C
F0,6C
0
45
F0,45
F7
83
F0,83
KP8
75
F0,75
1
16
F0,16
F8
0A
F0,0A
KP9
7D
F0,7D
2
1E
F0,1E
F9
01
F0,01
]
5B
F0,5B
3
26
F0,26
F10
09
F0,09
;
4C
F0,4C
4
25
F0,25
F11
78
F0,78
'
52
F0,52
5
2E
F0,2E
F12
07
F0,07
41
F0,41
6
36
F0,36
PRNT
SCRN
E0,12,
E0,7C
E0,F0,
7C,E0,
F0,12
.
49
F0,49
7
3D
F0,3D
SCROLL
7E
F0,7E
/
4A
F0,4A
8
3E
F0,3E
PAUSE
E1,14,77,
E1,F0,14,
F0,77
-NONE-
表2PC键盘第二套扫描码
2、设计思路
(1)PS2时钟的检测;
(2)PS2数据的接受并提取需要的8位数据;
(3)对PS2提取的8位数据进行解码,确定按键;
(4)通过LED灯显示按键的解码的结果;
(5)设置多个按键,多种LED显示方式;
对于PS2键盘扫描程序,我的设计思路是一个模块一个功能,这样能清晰分辨模块,同时易于修改代码。
代码条理清晰,便于解读。
而对于多个模块则使用层次化的形式来编写,顶层文件并不包含功能的设定,只包含各个子功能模块。
3、模块设计
PS2键盘扫描分为:
电平检测,PS2解码,PS2组合,LED控制和总PS组合六个模块。
下面为各个模块的简易模块图。
(1)PS2时钟检测模块:
图3电平检测模块图
(2)PS2解码模块:
图4PS2解码模块图
(3)PS2组合模块:
图5PS2组合模块图
(4)控制LED模块:
图6LED控制模块图
(5)PS2总的组合模块:
PS2_Done_Sig
PS2_Data
PS2_Data_Pin_In
PS2_CLK_Pin_In
Data_Out
电平检测模块
PS2_control_module
电平检测模块
PS2_control_module
图7PS2模块图
4、各模块分析
(1)PS2时钟检测模块
PS2电平检测模块主要的作用是检测PS2接口键盘的时钟信号,因为PS2的协议规定数据是在时钟的下降沿读取的。
所以电平检测模块要检测PS2时钟的下降沿,有下降沿来临时,要做相应的数据读取动作。
下面是代码的分析。
LIBRARYIEEE;--库
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
------------------------------------------------------------------------------------------------------------------------------------------
ENTITYPS2_detect_moduleIS--实体声明
PORT(
CLK,RSTn:
INSTD_LOGIC;
PS2_CLK_Pin_In:
INSTD_LOGIC;
H_L_Sig:
OUTSTD_LOGIC;--电平由高变低,输出一个信号
L_H_Sig:
OUTSTD_LOGIC--电平由低变高,输出一个信号
);
ENDENTITYPS2_detect_module;
------------------------------------------------------------------------------------------------------------------------------------------
ARCHITECTUREPS2_detectOFPS2_detect_moduleIS--结构体声明
SIGNALH_L_F1:
STD_LOGIC:
='1';--声明4个信号,用于电平输入的变化
SIGNALH_L_F2:
STD_LOGIC:
='1';--4个信号都赋了初值
SIGNALL_H_F1:
STD_LOGIC:
='0';
SIGNALL_H_F2:
STD_LOGIC:
='0';
BEGIN
PROCESS(CLK,RSTn)
BEGIN
IF(CLK'eventANDCLK='1')THEN--同步进行
IF(RSTn='0')THEN--同步复位动作
H_L_F1<='1';H_L_F2<='1';L_H_F1<='0';L_H_F2<='0';
ELSE
H_L_F1<=PS2_CLK_Pin_In;H_L_F2<=H_L_F1;
L_H_F1<=PS2_CLK_Pin_In;L_H_F2<=L_H_F1;
ENDIF;
ENDIF;
ENDPROCESS;
H_L_Sig<=H_L_F2AND(NOTH_L_F1);--输出信号
L_H_Sig<=L_H_F1AND(NOTL_H_F2);
ENDARCHITECTUREPS2_detect;--结构体结束
在结构体中声明了4个信号,用于电平的检测F2信号是接着F1信号的,如果F1信号变化了,F2信号还不会立即变化,F2还会保持F1的前一个状态,以两者的逻辑关系,可以判断输入的是上升沿还是下降沿。
结果如表格3。
时间
H_L_F1
H_L_F2
H_L_Sig<=H_L_F2AND(NOTH_L_F1)
Initial
1
1
0
T1
0
1
1
T2
0
0
0
时间
L_H_F1
L_H_F2
L_H_Sig<=L_H_F1AND(NOTL_H_F2);
Initial
0
0
0
T1
1
0
1
T2
1
1
0
表3电平检测变化表
(2)PS2解码模块
LIBRARYIEEE;--库
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
------------------------------------------------------------------------------------------------------------------------------------------
ENTITYPS2_decode_moduleIS--实体声明
PORT(
CLK,RSTn:
INSTD_LOGIC;
H_L_Sig:
INSTD_LOGIC;
PS2_Data_Pin_In:
INSTD_LOGIC;
PS2_Done_Sig:
OUTSTD_LOGIC;
PS2_Data:
OUTSTD_LOGIC_VECTOR(7DOWNTO0)
);
ENDENTITYPS2_decode_module;
------------------------------------------------------------------------------------------------------------------------------------------
ARCHITECTUREPS2_decodeOFPS2_decode_moduleIS
SIGNALDone:
STD_LOGIC:
='0';--声明一个完成信号
SIGNALi:
STD_LOGIC_VECTOR(4DOWNTO0):
="00001";--声明步骤i
SIGNALData:
STD_LOGIC_VECTOR(7DOWNTO0):
=X"32";
BEGIN
PROCESS(CLK,RSTn,i)
BEGIN
IF(CLK'eventANDCLK='1')THEN
IF(RSTn='0')THEN
i<="00001";Done<='0';Data<=X"00";
ELSE
CASEiIS
WHEN"00000"=>i<="00001";
WHEN"00001"=>IF(H_L_Sig='1')THENi<="00010";Data(0)<=PS2_Data_Pin_In;ENDIF;
WHEN"00010"=>IF(H_L_Sig='1')THENi<="00011";Data
(1)<=PS2_Data_Pin_In;ENDIF;
WHEN"00011"=>IF(H_L_Sig='1')THENi<="00100";Data
(2)<=PS2_Data_Pin_In;ENDIF;
WHEN"00100"=>IF(H_L_Sig='1')THENi<="00101";Data(3)<=PS2_Data_Pin_In;ENDIF;
WHEN"00101"=>IF(H_L_Sig='1')THENi<="00110";Data(4)<=PS2_Data_Pin_In;ENDIF;
WHEN"00110"=>IF(H_L_Sig='1')THENi<="00111";Data(5)<=PS2_Data_Pin_In;ENDIF;
WHEN"00111"=>IF(H_L_Sig='1')THENi<="01000";Data(6)<=PS2_Data_Pin_In;ENDIF;
WHEN"01000"=>IF(H_L_Sig='1')THENi<="01001";Data(7)<=PS2_Data_Pin_In;ENDIF;
WHEN"01001"=>IF(H_L_Sig='1')THENi<="01010";ENDIF;
WHEN"01010"=>IF(H_L_Sig='1')THENi<="01011";ENDIF;
WHEN"01011"=>IF(Data=X"F0")THENi<="01100";ELSEi<="10110";ENDIF;
WHEN"01100"=>IF(H_L_Sig='1')THENi<="01101";ENDIF;
WHEN"01101"=>IF(H_L_Sig='1')THENi<="01110";ENDIF;
WHEN"01110"=>IF(H_L_Sig='1')THENi<="01111";ENDIF;
WHEN"01111"=>IF(H_L_Sig='1')THENi<="10000";ENDIF;
WHEN"10000"=>IF(H_L_Sig='1')THENi<="10001";ENDIF;
WHEN"10001"=>IF(H_L_Sig='1')THENi<="10010";ENDIF;
WHEN"10010"=>IF(H_L_Sig='1')THENi<="10011";ENDIF;
WHEN"10011"=>IF(H_L_Sig='1')THENi<="10100";ENDIF;
WHEN"10100"=>IF(H_L_Sig='1')THENi<="10101";ENDIF;
WHEN"10101"=>IF(H_L_Sig='1')THENi<="10110";ENDIF;
WHEN"10110"=>IF(H_L_Sig='1')THENi<="10111";Done<='1';ENDIF;
WHEN"10111"=>IF(H_L_Sig='1')THENi<="00001";Done<='0';ENDIF;
WHENOTHERS=>i<="00001";
ENDCASE;
ENDIF;
ENDIF;
ENDPROCESS;
PS2_Data<=Data;
PS2_Done_Sig<=Done;
ENDARCHITECTUREPS2_decode;
这个模块我有点偷懒,只对键盘输入的8位有效数据进行了提取,其他位基本是忽略了,第一位开始位忽略了,然后是读取8位有效数据,第9步和第10步跳过了检测位和结束位,然后是判断。
如果是0XF0,则证明是断码,断码的话后面的直接跳过,如果不是0XF0,则证明是有效的数据,立即跳到步骤22,向顶层的模块回馈一个完成信号,并将有效数据输出。
(3)PS2组合模块
LIBRARYIEEE;
USEIEEE.STD_LOGIC_1164.ALL;
USEIEEE.STD_LOGIC_UNSIGNED.ALL;
------------------------------------------------------------------------------------------------------------------------------------------
ENTITYPS2IS
PORT(
CLK,RSTn:
INSTD_LOGIC;
PS2_Data_Pin_In:
INSTD_LOGIC;
PS2_CLK_Pin_In:
INSTD_LOGIC;
PS2_Done_Sig:
BUFFERSTD_LOGIC;
PS2_Data:
OUTSTD_LOGIC_VECTOR(7DOWNTO0)
);
ENDENTITYPS2;
------------------------------------------------------------------------------------------------------------------------------------------
ARCHITECTUREPS2_behaveOFPS2IS
COMPONENTPS2_detect_module
PORT(
CLK,RSTn:
INSTD_LOGIC;
PS2_CLK_Pin_In:
INSTD_LOGIC;
H_L_Sig:
OUTSTD_LOGIC;
L_H_Sig:
OUTSTD_LOGIC
);
ENDCOMPONENT;
COMPONENTPS2_decode_module
PORT(
CLK,RSTn:
INSTD_LOGIC;
H_L_Sig:
INSTD_LOGIC;
PS2_Data_Pin_In:
INSTD_LOGIC;
PS2_Done_Sig:
OUT