en为1时.置PA为“00000000”,en为0时,将tmp的相应位赋给输出端PA作为串并转换的结果。
程序见附录,波形仿真图如下:
2、扫描码转换成ASCII码
根据对照表将扫描码的数据转换成相对应的ASCII码,并判断是否有按键按下,且注意shift键和capslock键的状态对转换成ASCII码的不同结果的影响。
即首先判断通码和断码信号的到来与否,当信号为断码时无键按下无需进行转换;通码信号到来后根据所按下的键将扫描码转换成ASCII码;在此转换过程中同时对大小写字母的判断,条件为:
从A到Z之间满足shifted键和capslocked键都不按下时,或shifted键和capslocked键都按下时,并同时满足断码信号,此时将大写转换成小写即加0x20。
程序见附录,波形仿真图如下:
3、合并设计
将接收键盘数据产生扫描码的程序与把扫描码转换成ASCII码的程序合并在一起完成整个数据的转换及输出。
具体内容为:
将1中的PA接到2中的scan端,1中的ZHJS输出接到2中的prepared输入端。
使用component语句完成二者的连接。
器件连接如下:
二、扫描码显示过程
1、将产生的扫描码与ASCII码显示在数码管上
我们知道数码管显示数据的方式有静态显示和动态显示之分。
静态显示是将被显示的数据的BCD码通过各自的4-7/8显示译码器译码后,分别显示译码器的显示驱动段a-g(h)。
而动态显示则是将被显示的数据的BCD码,按照一定的变化频率,在不同的时刻周期性的分别送到一个数据总线上,再通过一个公共的4-7/8显示译码器后,接到多个显示译码器的公共显示驱动段a-g(h)上,同时,在不同的时刻周期性地选通对应的数码管的公共端。
在此使用动态显示,将输出扫描码和ASCII码的数据显示在数码管上。
程序见附录。
2、液晶显示扫描码及其所对应的ASCII码值
液晶显示是一种将液晶显示器件、连接件、集成电路、PCB线路板、背光源、结构件装配在一起的组件。
可组合成各种输入、显示、移位方式以满足不同要求。
其字符模块的电路框图如下图:
其字符模块功能主要有:
a)显示模式:
0x38:
16个字符x2行显示,5x7点阵,8位数据接口
b)显示开关及光标设置:
1.0x08~0x0b:
关显示
2.0x0c,0x0d:
开显示,但并不显示光标
3.0x0e:
开显示,显示光标,但不闪烁
4.0x0f:
开显示,显示光标,并闪烁
c)屏移设置:
1.0x04:
指针减1,整屏不移动
2.0x05:
指针减1,整屏左移
3.0x06:
指针加1,整屏不移动
4.0x07:
指针加1,整屏右移
d)数据指针设置(显示屏地址设置):
1.第一行地址码:
0x80+**
2.第二行地址码:
0x80+0x40+**
3.范围(00~27)
e)清零:
0x01:
数据指针清零,所有显示清零
f)回车:
0x02:
数据指针清零
g)读写操作:
写操作:
rs低电平r/w低电平en高电平
读操作:
rs高电平r/w高电平en高电平
h)显示数据:
rs高电平r/w低电平
将扫描码和ASCII码按上述功能显示在液晶屏上。
将十六进制的扫描码和ASCII码变换为两位十进制数,并在液晶显示中将其分别表示出来。
设计流程为:
初始化:
设置显示方式→开显示→AC自动加1→清屏→显示→送line1显示地址→显示数据→送line2显示地址→显示数据。
程序见附录。
结语:
上述用FPGA控制PS/2接口电路,PS/2接口协议是现在大多数键盘、鼠标与PC机通讯的标准协议。
其中鼠标对PC机的通讯更为简单,只是传输数据的内容不一样而已。
充分理解PS/2接口协议,巩固了对VHDL语言的运用,加深了对电子设计自动化这门课的理解,为以后更高层次的设计打下了坚实的基础。
可以帮助设计者自主开发一些工控机上的专用键盘等外设,并能够按照要求开发出专用的多功能键盘。
参考文献
1、侯伯亨.VHDL硬件描述语言与数字逻辑电路设计[M].西安:
西安电子科技大学出版社,1999.
2、赵世霞、杨丰、刘揭生。
VHDL与微机接口设计北京:
清华大学出版社2004
3、林敏.VHDL数字系统设计与高层次综合[M].北京:
电子工业出版社,2001.
4、卢毅.VHDL与数字电路设计[M].北京:
科学出版社,2001.
5、张琴.向先波.徐国率PS/2键盘在基于PIC单片机的远程多温度点巡检系统中的应用[期刊论文]-机械与电子2006(08)
6、苗新法.王秀隼PS/2键盘在嵌入式系统中的应用研究[期刊论文]-兰州交通大学学报2007(01)
7、徐晓.汪道辉标准PS/2键盘与单片机的接口设计[期刊论文]-中国测试技术2005(01)
8、郑炜.须文波.胡晋单片机系统中PS/2键盘驱动程序设计[期刊论文]-单片机与嵌入式系统2005
顶层文件:
一、键盘扫描过程
1接收键盘数据并转换为扫描码程序代码:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
useieee.std_logic_arith.all;
entitykbis
port(rst:
instd_logic;--复位键,低电平有效
s_clk:
instd_logic;--系统时钟
k_clk:
instd_logic;--键盘时钟
k_data:
instd_logic;--数据
PA:
bufferstd_logic_vector(7downto0);--扫描码输出
ZHJS:
outstd_logic--扫描码转换结束信号转换结束时置低
);
end;
architectureoneofkbis
signaltmp:
std_logic_vector(11downto0):
=(others=>'0');--记录每一帧的数据
signalp_kbclk,c_kbclk:
std_logic;
signalen:
std_logic;--输出使能
begin
process(rst,s_clk,k_clk)--得到键盘发送的有效数据扫描码
variablecnt:
integerrange0to11:
=0;
variablestart:
std_logic:
='0';
begin
ifrst='0'thencnt:
=0;ZHJS<='0';
elsifrising_edge(s_clk)then
p_kbclk<=c_kbclk;
c_kbclk<=k_clk;
ifp_kbclk>c_kbclkthentmp(cnt)<=k_data;
ifcnt=10thenZHJS<='0';
elseZHJS<='1';
endif;
ifcnt=11then
cnt:
=1;
elsecnt:
=cnt+1;
endif;
endif;
ifcnt>=1andcnt<10then
start:
='1';
elsestart:
='0';
endif;
endif;
en<=start;
endprocess;
PA<=(others=>'0')whenen='1'else
tmp(8downto1);
end;
二、扫描码转换成ASCII码
D触发器源程序代码:
libraryieee;
useieee.std_logic_1164.all;
entitymydis
port(clk,data:
instd_logic;
q:
outstd_logic);
end;
architectureoneofmydis
begin
process(clk)
begin
if(rising_edge(clk))then
q<=data;
endif;
endprocess;
end;
扫描码转换成ASCII码程序代码:
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_unsigned.all;
useieee.std_logic_arith.all;
entityconvertis
port(scan:
instd_logic_vector(7downto0);
prepared:
instd_logic;
clr:
instd_logic;
rd:
instd_logic;
intr:
outstd_logic;
cs_2:
instd_logic;
data:
outstd_logic_vector(7downto0));
end;
architectureoneofconvertis
componentmydis
port(clk,data:
instd_logic;
q:
outstd_logic);
endcomponent;
signaltmp:
integerrange0to16#7F#;
--保存转换好的ASCII码的整数值
signalASCII:
std_logic_vector(7downto0);
--保存转换好的ASCII
signalkey_d:
std_logic:
='0';
signalshift_d:
std_logic:
='0';
signalcapslock_d:
std_logic:
='0';
signalkey:
std_logic:
='0';
signalshifted:
std_logic:
='0';
signalcapslocked:
std_logic:
='0';
begin
key_d<='1'whenscan=x"F0"--断码信号
else'0';
shift_d<='0'whenclr='0'
else
notshiftedwhen(scan=x"58"andscan=x"59")
--扫描码位58或59时shift键转换,进行大小写字母变换(0表小写,1表大写)
elseshifted;
capslock_d<='0'whenclr='0'
else
notcapslockedwhenscan=x"58"andkey='1'
elsecapslocked;--大小写字母控制键(0表小写,1表大写)
tmp<=
16#09#whenscan="00001101"else
16#60#whenscan="00001110"andshifted='0'else
16#7E#whenscan="00001110"andshifted='1'else
16#51#whenscan="00010101"else
16#31#whenscan="00010110"andshifted='0'else
16#21#whenscan="00010110"andshifted='1'else
16#5A#whenscan="00011010"else
16#53#whenscan="00011011"else
16#41#whenscan="00011100"else
16#57#whenscan="00011101"else
16#32#whenscan="00011110"andshifted='0'else
16#40#whenscan="00011110"andshifted='1'else
16#43#whenscan="00100001"else
16#58#whenscan="00100010"else
16#44#whenscan="00100011"else
16#45#whenscan="00100100"else
16#34#whenscan="00100101"andshifted='0'else
16#24#whenscan="00100101"andshifted='1'else
16#33#whenscan="00100110"andshifted='0'else
16#23#whenscan="00100110"andshifted='1'else
16#20#whenscan="00101001"else
16#56#whenscan="00101010"else
16#46#whenscan="00101011"else
16#54#whenscan="00101100"else
16#52#whenscan="00101101"else
16#35#whenscan="00101110"andshifted='0'else
16#25#whenscan="00101110"andshifted='1'else
16#4E#whenscan="00110001"else
16#42#whenscan="00110010"else
16#48#whenscan="00110011"else
16#47#whenscan="00110100"else
16#59#whenscan="00110101"else
16#36#whenscan="00110110"andshifted='0'else
16#5E#whenscan="00110110"andshifted='1'else
16#4D#whenscan="00111010"else
16#4A#whenscan="00111011"else
16#55#whenscan="00111100"else
16#37#whenscan="00111101"andshifted='0'else
16#26#whenscan="00111101"andshifted='1'else
16#38#whenscan="00111110"andshifted='0'else
16#2A#whenscan="00111110"andshifted='1'else
16#2C#whenscan="010000