键盘接口控制器设计.docx
《键盘接口控制器设计.docx》由会员分享,可在线阅读,更多相关《键盘接口控制器设计.docx(27页珍藏版)》请在冰豆网上搜索。
![键盘接口控制器设计.docx](https://file1.bdocx.com/fileroot1/2023-6/15/2e428185-bdf6-4093-916f-71284d30ea47/2e428185-bdf6-4093-916f-71284d30ea471.gif)
键盘接口控制器设计
PS/2键盘接口控制器设计
班级
姓名:
学号:
班内序号:
时间:
课题名称:
PS/2键盘接口控制器设计
一、摘要和关键词
摘要:
PS/2是在电脑上常见的接口之一,用于鼠标、键盘等设备。
PS/2接口是输入装置接口,而不是传输接口,所以PS/2口只有扫描速率。
在Windows环境下,PS/2鼠标的采样率默认为60次/秒。
微控制器所要作的工作就是监测所有的按键,以及当按键被按下或放开时,就回报给主机。
本实验中,通过数字可编程芯片模拟控制器将键盘的输入分别输出到数码管和点阵显示。
关键词:
PS/2接口点阵数码管数字可编程芯片
二、设计任务要求
设计制作一个PS/2键盘接口控制器,实现以下功能:
1.按照PS/2键盘接口标准设计一个控制器,接收PS/2键盘发送的数据,用数码管显示接收到的键值(只显示0~9,a~z,部分不便用数码管显示的字符可自行设定显示方式,接收到其他键值则不显示);
2.用8×8点阵做显示屏,显示所有按键的键值。
三、设计思路、总体结构框图
1.设计思路:
带PS/2接口的键盘与实验开发板连接后,通过可编程芯片读取键盘输入的键值,通过数据线分别传送至数码管和8*8点阵显示。
在实验中,分三个模块实现实验所要求的功能:
检测键盘输入键值模块、数码管显示模块、8*8点阵显示模块。
将三个模块分别设计好后,组合在一起,即可实现实验所要求的功能。
2.总体结构框图:
四、控制器部分的状态转移图和流程图
1.控制器部分的状态转移图如下图所示(其中状态值是shift_in的值,假设本次传输的字节数据值是11010011,传输其他字节数据信息时,同理,只需修改shift_in值即可):
2.控制器部分的流程图如下图所示:
五、分块电路和总体电路设计
分三个模块实现实验所要求的功能:
检测键盘输入键值模块、数码管显示模块、8*8点阵显示模块。
其组合关系如下图所示:
实验完成后的总体效果图如下图所示:
1.检测键盘输入键值模块设计
检测带PS/2接口的键盘输入时,需要按照特定的步骤来执行操作,才能正确地读取键盘输入的键值。
严格的读取数据步骤为:
1)等待键盘时钟信号clock=high;
2)延时50微秒;
3)键盘时钟信号clock仍旧为high?
No则回到第1步,Yes则向下执行;
4)数据控制信号data=high?
No则放弃(并且从主机读取字节),Yes则向下执行;
5)延迟20微秒(若正在发送起始位则延时40微秒);
6)输出起始位bit(0)(在发送所有这些位的每一位后都要检测时钟线);
7)输出8个数据位(测试时钟确认主机是否把时钟线拉低了);
8)输出校验位;
9)输出停止位,延迟30毫秒。
而按如下的过程发送单个位
1)设置复位数据;2)延迟20微秒;3)把时钟拉低;4)延迟40微秒;5)释放时钟;6)延迟20微秒。
通过实际情况修正与改进以上步骤,在本实验中采用的读取键盘输入键值模块的VHDL语言编程的流程图如下图所示:
2.数码管显示模块设计
当需要在一个数码管上显示字符时只要在数据端需要点亮的字段管脚上输入’1’,不需要点亮的字段输入管脚上输入’0’,同时把相应的控制端置为’0’即可。
当键盘键值和数字0~9的通码比较后,即可送往数码管显示。
数字0~9对应的a~g、p的高低电平如下表所示:
数字
a
b
c
d
e
f
g
p
0
1
1
1
1
1
1
0
0
1
0
1
1
0
0
0
0
0
2
1
1
0
1
1
0
1
0
3
1
1
1
1
0
0
1
0
4
0
1
1
0
0
1
1
0
5
1
0
1
1
0
1
1
0
6
1
0
1
1
1
1
1
0
7
1
1
1
0
0
0
0
0
8
1
1
1
1
1
1
1
0
9
1
1
1
1
0
1
1
0
数码管功能原理图如下图所示:
3.8*8点阵显示模块
点阵是由8行8列一共64个发光二极管构成。
一共对外的管脚有16条,分为行ROW1~ROW8和列COL1~COL8。
点亮EPM1270TCC54芯片上的点阵上某一个点的条件是对应该点的行管脚输出高电平,列管脚输出低电平。
利用点阵显示某个字符时,需要先计算出需要点亮点阵的哪些点,再使用行扫描的扫描方式对点阵逐行扫描,即可显示所需要显示的字符,其流程图如下所示:
六、所实现功能说明
1.已完成的基本功能和扩展功能:
1)可分别用拨码开关SW0~SW5控制是否使用数码管DSP1~DSP6显示数字键值,数码管可显示数字0~9;
2)可用SW7控制是否使用8*8点阵显示键值,点阵可显示数字0~9、字母A~Z;
3)可用SW6控制是否读取键盘输入的键值。
2.器件资源占用情况:
使用了41个管脚接口,如下图所示:
使用了336个宏单元,如下图所示:
3.关键波形仿真:
在进行波形仿真时,由于本实验模拟PS/2控制器的特殊性,输入的主要数据是keyboard_data,每次读取1位数据,在波形仿真时,输出的是键盘键值的通码,输入输出的数据的位数不一致(keyboard_data是1位,而输出是8位),
由于仿真时系统的时钟不能太快,否则仿真时间会特别长导致软件崩溃,故在仿真波形上只能看到点阵中第一行的波形
4.测试方法与步骤:
主要按以下步骤进行本系统的调试与改进:
1)键盘与实验开发板之间连接好;
2)单独编写数码管显示程序,利用数码管显示特定的数字;
3)单独编写点阵显示程序,利用点阵显示特定的字符;
4)编写键盘输入键值读取程序,并和数码管程序结合起来,把输出数据送至数码管显示。
这时,就可以根据数码管显示的字符是否正确来改进键盘输入键值读取程序,只要数码管能正确显示一个数字,显示其余的数字也就是重复相同的原理而已;
5)在前面4步调试好后,把三个模块检测键盘输入键值模块、数码管显示模块、8*8点阵显示模块的程序组合起来即可。
七、故障及问题分析
在编写检测键盘输入键值模块的VHDL程序时,按照参考资料上的特定步骤,并不能正确地读取键盘输入的键值。
问题分析:
对于两份PDF参考资料上关于PS/2设备向主机发送一个字节和一位数据的描述,其是建立在向主机(计算机)发送的基础上的,而本实验中利用数字电路实验开发板模拟PS/2控制器,数字芯片可以直接从键盘数据输入口读取数据,省去了很多不必需的步骤:
1)校验位和停止位:
由于起始位始终为0,数据位为8位,而检验位与停止位读取与否并不影响该程序的功能实现,所以只需读取PS/2键盘的起始位和数据位,并且最终将8位数据位转存入data_cade和data_code1。
这样,既不影响程序功能的正确实现,又能精简程序代码。
2)时钟信号电平:
在参考资料中,在读取数据位时,要求时钟信号为高。
但在实际编程仿真中发现:
在等待时钟信号时,它的电平高低对后来的读取数据并没有影响。
这也是本次实验的特殊之处,同样,对于数据位的高低电平也不必强制要求。
3)延时问题:
在参考资料中,反复提到读取数据位过程中的延时,但在编程中发现并不需要设置延时,而同样能正确地读取了键盘输入的数据。
在使用VHDL语言编程、利用数字可编程芯片仿真PS/2控制器时,并不需要专门的延时时间,键盘数据是每一位连续传向数据线的,其中指令的执行时间已经足够控制芯片读取数据的缓冲时间。
八、总结和结论
通过这次数电实验,我进一步加深了对可编程逻辑器件的认识,熟练掌握了quartusii软件的使用方法,包括编程,仿真下载测试。
并且系统的学习了VHDL语言。
同时,学习了PS/2协议,了解了PS/2键盘是如何向主机传输数据的,也解开了我从小到大一直的疑惑。
九、参考文献
1《PS/2键盘协议》
2《数字电路与逻辑设计实验教程》
北京邮电大学电子工程学院电路实验中心
2009年3月
十、源程序
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
useieee.std_logic_unsigned.all;
entitykeyboardis
port(
keyboard_clk,keyboard_data,key_stop:
instd_logic;
--键盘时钟信号,1位数据信号,终止键盘输入信号
clk:
instd_logic;--系统时钟信号
led_clr:
instd_logic;--点阵显示复位信号
led_code:
outstd_logic_vector(7downto0);--接收到的送数码管显示的8位数据信号
cat:
outstd_logic_vector(5downto0);--控制哪个数码管显示
swcat:
instd_logic_vector(5downto0);--利用拨码开关控制哪个数码管显示
row:
outstd_logic_vector(7downto0);--行通量
col:
outstd_logic_vector(7downto0));--列通量
endkeyboard;
architectureaofkeyboardis
signalcounter:
std_logic_vector(3downto0);--计数器
signalshift_in:
std_logic_vector(8downto0);--包含1个起始位和8个数据位
signalread_bit:
std_logic;--是否读取数据控制信号
signaldata_code:
std_logic_vector(7downto0);--8位数据信号
signaldata_code1:
std_logic_vector(7downto0);--点阵显示
signaltemp:
integerrange1to8;--列扫描控制信号
signalt:
std_logic;
signalclkout:
std_logic;
begin
process(clk)--1K分频器
variablecount:
integerrange0to1000;
begin
if(clk'eventandclk='1')then
if(count=499)then
count:
=0;
t<=nott;
else
count:
=count+1;
endif;
endif;
clkout<=t;
endprocess;
process
begin
waituntil(keyboard_clk'eventandkeyboard_clk='0');--等待键盘时钟信号为低电平
ifkey_stop='1'then--终止键盘输入
counter<="0000";--计数器设置为0
read_bit<='0';--读取数据控制信号为低电平
else
ifkeyboard_data='0'andread_bit='0'then--数据线信号为低电平且读取数据控制信号为低电平
read_bit<='1';--则开始读取数据位
else
ifread_bit='1'then--开始处理8个数据位
ifcounter<"1001"then--计数器小于1001时
counter<=counter+1;--计数器加1
shift_in(7downto0)<=shift_in(8downto1);--每次不读取shift_in(0)(该位为起始位)
shift_in(8)<=keyboard_data;--读取新的数据位
else
data_code<=shift_in(7downto0);--存储8位数据信号
data_code1<=shift_in(7downto0);--存储8位数据信号
read_bit<='0';--读取数据控制信号置0
counter<="0000";--计数器置0
endif;
endif;
endif;
endif;
endprocess;
process(data_code)--数据送数码管显示
begin
cat<=swcat;--控制数码显示管显示
casedata_codeis
when"01000101"=>led_code<="11111100";--0
when"00010110"=>led_code<="01100000";--1
when"00011110"=>led_code<="11011010";--2
when"00100110"=>led_code<="11110010";--3
when"00100101"=>led_code<="01100110";--4
when"00101110"=>led_code<="10110110";--5
when"00110110"=>led_code<="10111110";--6
when"00111101"=>led_code<="11100000";--7
when"00111110"=>led_code<="11111110";--8
when"01000110"=>led_code<="11110110";--9
whenothers=>led_code<="00000000";
endcase;
endprocess;
process(data_code1,clkout)--数据送led点阵显示
begin
ifled_clr='1'then--复位
row<="00000000";
col<="00000000";
temp<=1;
else
casetempis
when1=>
row<="01111111";--扫描第1行
casedata_code1is
when"01000101"=>col<="00111100";--0
when"00010110"=>col<="00011000";--1
when"00011110"=>col<="01111110";--2
when"00100110"=>col<="01111110";--3
when"00100101"=>col<="00011100";--4
when"00101110"=>col<="00100000";--5
when"00110110"=>col<="00011100";--6
when"00111101"=>col<="00111110";--7
when"00111110"=>col<="01111110";--8
when"01000110"=>col<="00111100";--9
when"00011100"=>col<="00011000";--A
when"00110010"=>col<="00000000";--B
when"00100001"=>col<="00011100";--C
when"00100011"=>col<="01111000";--D
when"00100100"=>col<="01111110";--E
when"00101011"=>col<="01111110";--F
when"00110100"=>col<="00111100";--G
when"00110011"=>col<="01000010";--H
when"01000011"=>col<="00111000";--I
when"00111011"=>col<="00011100";--J
when"01000010"=>col<="01000100";--K
when"01001011"=>col<="00100000";--L
when"00111010"=>col<="01101100";--M
when"00110001"=>col<="10000001";--N
when"01000100"=>col<="00111000";--O
when"01001101"=>col<="01111100";--P
when"00010101"=>col<="00111000";--Q
when"00101101"=>col<="01111100";--R
when"00011011"=>col<="00011100";--S
when"00101100"=>col<="11111110";--T
when"00111100"=>col<="01000010";--U
when"00101010"=>col<="01000001";--V
when"00011101"=>col<="10010010";--W
when"00100010"=>col<="10000001";--X
when"00110101"=>col<="10000010";--Y
when"00011010"=>col<="11111111";--Z
whenothers=>col<="00000000";
endcase;
when2=>
row<="10111111";--扫描第2行
casedata_code1is
when"01000101"=>col<="01000010";--0
when"00010110"=>col<="00101000";--1
when"00011110"=>col<="00000010";--2
when"00100110"=>col<="00000010";--3
when"00100101"=>col<="00100000";--4
when"00101110"=>col<="00111110";--5
when"00110110"=>col<="00100000";--6
when"00111101"=>col<="01000010";--7
when"00111110"=>col<="01000010";--8
when"01000110"=>col<="01000010";--9
when"00011100"=>col<="00100100";--A
when"00110010"=>col<="01111100";--B
when"00100001"=>col<="00100010";--C
when"00100011"=>col<="01000100";--D
when"00100100"=>col<="01000000";--E
when"00101011"=>col<="01000000";--F
when"00110100"=>col<="01000010";--G
when"00110011"=>col<="01000010";--H
when"01000011"=>col<="00010000";--I
when"00111011"=>col<="00001000";--J
when"01000010"=>col<="01001000";--K
when"01001011"=>col<="00100000";--L
when"00111010"=>col<="10010010";--M
when"00110001"=>col<="11000001";--N
when"01000100"=>col<="01000100";--O
when"01001101"=>col<="01000010";--P
when"00010101"=>col<="01000100";--Q
when"00101101"=>col<="01000010";--R
when"00011011"=>col<="00100010";--S
when"00101100"=>col<="00010000";--T
when"00111100"=>col<="01000010";--U
when"00101010"=>col<="01000001";--V
when"00011101"=>col<="10010010";--W
when"00100010"=>col<="01000010";--X
when"00110101"=>col<="01000100";--Y
when"00011010"=>col<="00000010";--Z
whenothers=>col<="00000000";
endcase;
when3=>
row<="11011111";--扫描第3行
casedata_code1is
when"01000101"=>col<="01000010";--0
when"00010110"=>col<="00001000";--1
when"00011110"=>col<="00000010";--2
when"00100110"=>col<="00000010";--3
when"00100101"=>col<="01000000";--4
when"00101110"=>col<="00100000";--5
when"00110110"=>col<="01000000";--6
when"00111101"=>col<="00000100";--7
when"00111110"=>col<="01000010";--8
when"01000