ps2键盘协议资料.docx
《ps2键盘协议资料.docx》由会员分享,可在线阅读,更多相关《ps2键盘协议资料.docx(14页珍藏版)》请在冰点文库上搜索。
ps2键盘协议资料
一.电气特性
1
DATA
KeyData
2
n/c
Notconnected
3
GND
Gnd
4
VCC
Power,+5VDC
5
CLK
Clock
6
n/c
Notconnected
二.数据格式
1个起始位
总是逻辑0
8个数据位
(LSB)低位在前
1个奇偶校验位
奇校验
1个停止位
总是逻辑1
1个应答位
仅用在主机对设备的通讯中
表中,如果数据位中1的个数为偶数,校验位就为1;如果数据位中1的个数为奇数,校验位就为0;总之,数据位中1的个数加上校验位中1的个数总为奇数,因此总进行奇校验。
ps2设备的clock和data都是集电极开路的,平时都是高电平。
当ps2设备等待发送数据时,它首先检查clock是否为高。
如果为低,则认为PC抑制了通讯,此时它缓冲数据直到获得总线的控制权。
如果clock为高电平,ps2则开始向PC发送数据。
一般都是由ps2设备产生时钟信号。
发送按帧格式。
数据位在clock为高电平时准备好,在clock下降沿被PC读入。
数据从键盘/鼠标发送到主机或从主机发送到键盘/鼠标,时钟都是PS2设备产生.主机对时钟控制有优先权,即主机想发送控制指令给PS2设备时,可以拉低时钟线至少100μS,然后再下拉数据线,最后释放时钟线为高。
PS2设备的时钟线和数据线都是集电极开路的,容易实现拉低电平。
PC在时钟的下降沿读取数据.
PS:
ps2协议是现在大多数鼠标,键盘与PC通讯的标准协议,鼠标的通讯更为简单些,只是传送的数据内容不一样而已。
三.数据发送时序
键盘接口时序(a)键盘发送时序;(b)键盘接收时序
从PS/2向PC机发送一个字节可按照下面的步骤进行:
(1)检测时钟线电平,如果时钟线为低,则延时50μs;
(2)检测判断时钟信号是否为高,为高,则向下执行,为低,则转到(1);
(3)检测数据线是否为高,如果为高则继续执行,如果为低,则放弃发送(此时PC机在向PS/2设备发送数据,所以PS/2设备要转移到接收程序处接收数据);
(4)延时20μs(如果此时正在发送起始位,则应延时40μs);
(5)输出起始位(0)到数据线上。
这里要注意的是:
在送出每一位后都要检测时钟线,以确保PC机没有抑制PS/2设备,如果有则中止发送;
(6)输出8个数据位到数据线上;
(7)输出校验位;
(8)输出停止位(1);
(9)延时30μs(如果在发送停止位时释放时钟信号则应延时50μs);
通过以下步骤可发送单个位:
(1)准备数据位(将需要发送的数据位放到数据线上);
(2)延时20μs;
(3)把时钟线拉低;
(4)延时40μs;
(5)释放时钟线;
(6)延时20μs。
PS/2设备从PC机接收一个字节
由于PS/2设备能提供串行同步时钟,因此,如果PC机发送数据,则PC机要先把时钟线和数据线置为请求发送的状态。
PC机通过下拉时钟线大于100μs来抑制通讯,并且通过下拉数据线发出请求发送数据的信号,然后释放时钟。
当PS/2设备检测到需要接收的数据时,它会产生时钟信号并记录下面8个数据位和一个停止位。
主机此时在时钟线变为低时准备数据到数据线,并在时钟上升沿锁存数据。
而PS/2设备则要配合PC机才能读到准确的数据。
具体连接步骤如下:
(1)等待时钟线为高电平。
(2)判断数据线是否为低,为高则错误退出,否则继续执行。
(3)读地址线上的数据内容,共8个bit,每读完一个位,都应检测时钟线是否被PC机拉低,如果被拉低则要中止接收。
(4)读地址线上的校验位内容,1个bit。
(5)读停止位。
(6)如果数据线上为0(即还是低电平),PS/2设备继续产生时钟,直到接收到1且产生出错信号为止(因为停止位是1,如果PS/2设备没有读到停止位,则表明此次传输出错)。
(7输出应答位。
(8)检测奇偶校验位,如果校验失败,则产生错误信号以表明此次传输出现错误。
(9)延时45μs,以便PC机进行下一次传输。
读数据线的步骤如下:
(1)延时20μs;
(2)把时钟线拉低
(3)延时40μs
(4)释放时钟线
(5)延时20μs
(6)读数据线。
下面的步骤可用于发出应答位;
(1)延时15μs;(2)把数据线拉低;(3)延时5μs;(4)把时钟线拉低;(5)延时40μs;(6)释放时钟线;(7)延时5μs;(8)释放数据线。
四.键盘返回值介绍:
键盘的处理器如果发现有键被按下或释放将发送扫描码的信息包到计算机。
扫描码有两种不同的类型:
通码和断码。
当一个键被按下就发送通码,当一个键被释放就发送断码。
每个按键被分配了唯一的通码和断码。
这样主机通过查找唯一的扫描码就可以测定是哪个按键。
每个键一整套的通断码组成了扫描码集。
有三套标准的扫描码集:
分别是第一套,第二套和第三套。
所有现代的键盘默认使用第二套扫描码。
虽然多数第二套通码都只有一个字节宽,但也有少数扩展按键的通码是两字节或四字节宽。
这类的通码第一个字节总是为E0。
正如键按下通码就被发往计算机一样,只要键一释放断码就会被发送。
每个键都有它自己唯一的通码和断码。
幸运的是你不用总是通过查表来找出按键的断码。
在通码和断码之间存在着必然的联系。
多数第二套断码有两字节长。
它们的第一个字节是F0,第二个字节是这个键的通码。
扩展按键的断码通常有三个字节,它们前两个字节是E0h,F0h,最后一个字节是这个按键通码的最后一个字节。
下面列出了几个按键的第二套通码和断码:
No.
KEY
通码(第二套)
断码(第二套)
1
"A"
1C
F01C
2
"5"
2E
F02E
3
"F10"
09
F009
4
RightArrow
E074
E0F074
5
Right"Ctrl"
E014
E0F014
一个键盘发送值的例子:
通码和断码是以什么样的序列发送到你的计算机从而使得字符G出现在你的字处理软件里的呢?
因为这是一个大写字母,需要发生这样的事件次序:
按下Shift键-按下G键-释放G键-释放Shift键。
与这些时间相关的扫描码如下:
Shift键的通码12h,G键的通码34h,G键的断码F0h34h,Shift键的断码F0h12h。
因此发送到你的计算机的数据应该是:
12h34hF0h34hF0h12h
五:
第二套扫描码:
101102和104键的键盘:
KEY
通码
断码
KEY
通码
断码
KEY
通码
断码
A
1C
F01C
9
46
F046
[
54
F054
B
32
F032
`
0E
F00E
INSERT
E070
E0F070
C
21
F021
-
4E
F04E
HOME
E06C
E0F06C
D
23
F023
=
55
F055
PGUP
E07D
E0F07D
E
24
F024
\
5D
F05D
DELETE
E071
E0F071
F
2B
F02B
BKSP
66
F066
END
E069
E0F069
G
34
F034
SPACE
29
F029
PGDN
E07A
E0F07A
H
33
F033
TAB
0D
F00D
UARROW
E075
E0F075
I
43
F043
CAPS
58
F058
LARROW
E06B
E0F06B
J
3B
F03B
LSHFT
12
F012
DARROW
E072
E0F072
K
42
F042
LCTRL
14
F014
RARROW
E074
E0F074
L
4B
F04B
LGUI
E01F
E0F01F
NUM
77
F0 77
M
3A
F03A
LALT
11
F011
KP/
E04A
E0F04A
N
31
F031
RSHFT
59
F059
KP*
7C
F0 7C
O
44
F044
RCTRL
E014
E0F014
KP-
7B
F07B
P
4D
F04D
RGUI
E027
E0F027
KP+
79
F079
Q
15
F015
RALT
E011
E0F011
KPEN
E05A
E0F05A
R
2D
F02D
APPS
E02F
E0F02F
KP
71
F071
S
1B
F01B
ENTER
5A
F05A
KP0
70
F070
T
2C
F02C
ESC
76
F076
KP1
69
F069
U
3C
F03C
F1
05
F005
KP2
72
F072
V
2A
F02A
F2
06
F006
KP3
7A
F07A
W
1D
F01D
F3
04
F004
KP4
6B
F06B
X
22
F022
F4
0C
F00C
KP5
73
F073
Y
35
F035
F5
03
F003
KP6
74
F074
Z
1A
F01A
F6
0B
F00B
KP7
6C
F06C
0
45
F045
F7
83
F083
KP8
75
F075
1
16
F016
F8
0A
F00A
KP9
7D
F07D
2
1E
F01E
F9
01
F001
]
58
F058
3
26
F026
F10
09
F009
;
4C
F04C
4
25
F025
F11
78
F078
'
52
F052
5
2E
F02E
F12
07
F007
41
F041
6
36
F036
PRNT
SCRN
E012
E07C
E0F0
7CE0
F012
.
49
F049
7
3D
F03D
SCROLL
7E
F0,7E
/
4A
F04A
8
3E
F03E
PAUSE
E11477
E1F014
F077
-NONE-
ACPI扫描码:
KEY
通码
断码
Power
E0,37
E0,F0,37
Sleep
E0,3F
E0,F0,3F
Wake
E0,5E
E0,F0,5E
Windows多媒体扫描码:
KEY
通码
断码
NextTrack
E0,4D
E0,F0,4D
PreviousTrack
E0,15
E0,F0,15
Stop
E0,3B
E0,F0,3B
Play/Pause
E0,34
E0,F0,34
Mute
E0,23
E0,F0,23
VolumeUp
E0,32
E0,F0,32
VolumeDown
E0,21
E0,F0,21
MediaSelect
E0,50
E0,F0,50
E-Mail
E0,48
E0,F0,48
Calculator
E0,2B
E0,F0,2b
MyComputer
E0,40
E0,F0,40
WWWSearch
E0,10
E0,F0,10
WWWHome
E0,3A
E0,F0,3a
WWWBack
E0,38
E0,F0,38
WWWForward
E0,30
E0,F0,20
WWWStop
E0,28
E0,F0,28
WWWRefresh
E0,20
E0,F0,20
WWWFavorites
E0,18
E0,F0,18
****************************************************************************************
PS2读电脑键盘实验*
连接方法:
P0口与J12连接拔开跳线帽用杜邦线连接左针与P3.2右针与P1.6连接*
使用方法:
用外部中断读取PS2键盘的数据并在数码管上显示,此程序只处理数字键盘。
*
*
其余按键功能用户可以自行扩展,为了程序简单便于阅读和学习,程序中没有使用奇偶校验,*
校验程序请自行添加。
**
*
*****************************************************************************************/
#include
sbitLS138A=P2^2;
sbitLS138B=P2^3;
sbitLS138C=P2^4;
sbitBEEP=P1^5;
sbitKey_Data=P1^6;//定义键盘引脚
sbitKey_CLK=P3^2;//使用外部中断
/******************************************************************/
/*函数声明*/
/******************************************************************/
voidDecode(unsignedcharScanCode);//解码子程序
voiddelay(unsignedinti);//函数声名
voiddisplay();
voidbeep();
//此表为LED的字模//0123456789AbcdE-LPUHidden_(20)
unsignedcharcodeDisp_Tab[]={~0xC0,~0xF9,~0xA4,~0xB0,~0x99,~0x92,~0x82,~0xF8,~0x80,~0x90,~0x88,~0x83,~0xC6,~0xA1,~0x86,~0xbf,~0xc7,~0x8c,~0xc1,~0xff,~0xf7};
bitBF;
unsignedcharKeyV;
unsignedcharLedNumVal;
intKEY_val,IntNum;
/******************************************************************/
/*主函数*/
/******************************************************************/
voidmain()
{
IT1=0;//设外部中断1为低电平触发
EA=1;//外部中断开
EX0=1;//开中断
while
(1)
{
if(BF)
{
if(KeyV!
=240)beep();
Decode(KeyV);//解码
}
else
EA=1;//开中断
display();
}
}
/******************************************************************/
/*外部中断读入信息*/
/******************************************************************/
voidKeyboard_out(void)interrupt0
{
if((IntNum>0)&&(IntNum<9))
{
KeyV=KeyV>>1;//因键盘数据是低>>高,结合上一句所以右移一位
if(Key_Data)
KeyV=KeyV|0x80;//当键盘数据线为1时到最高位
}
IntNum++;
while(!
Key_CLK);//等待PS/2CLK拉高
if(IntNum>10)
{
IntNum=0;//当中断11次后表示一帧数据收完,清变量准备下一次接收
BF=1;//标识有字符输入完了
EA=0;//关中断等显示完后再开中断
}
}
/******************************************************************/
/*解码信息*/
/******************************************************************/
voidDecode(unsignedcharScanCode)//注意:
如SHIFT+G为12H34HF0H34HF0H12H,也就是说shift的通码+G的通码+shift的断码+G的断码
{
switch(ScanCode)
{
case0x70:
//当收到0xF0,Key_UP置1表示断码开始
KEY_val=0;
break;
case0x69:
KEY_val=1;
break;
case0x72:
KEY_val=2;
break;
case0x7A:
KEY_val=3;
break;
case0x6B:
KEY_val=4;
break;
case0x73:
KEY_val=5;
break;
case0x74:
KEY_val=6;
break;
case0x6c:
KEY_val=7;
break;
case0x75:
KEY_val=8;
break;
case0x7d:
KEY_val=9;
break;
case0x71:
//dot=0X7F;
break;
}
BF=0;//标识字符处理完了
}
/***************************************************************************************/
voiddisplay()
{
unsignedchari;
unsignedintLedOut[8];
LedNumVal=KEY_val;
LedOut[0]=Disp_Tab[LedNumVal%10000/1000];
LedOut[1]=Disp_Tab[LedNumVal%1000/100];
LedOut[2]=Disp_Tab[LedNumVal%100/10];
LedOut[3]=Disp_Tab[LedNumVal%10];
LedOut[4]=Disp_Tab[LedNumVal%10000/1000];//千位
LedOut[5]=Disp_Tab[LedNumVal%1000/100];//百位带小数点
LedOut[6]=Disp_Tab[LedNumVal%100/10];//十位
LedOut[7]=Disp_Tab[LedNumVal%10];//个位
for(i=0;i<8;i++)
{P0=LedOut[i];
switch(i)
{
case0:
LS138A=0;LS138B=0;LS138C=0;break;
case1:
LS138A=1;LS138B=0;LS138C=0;break;
case2:
LS138A=0;LS138B=1;LS138C=0;break;
case3:
LS138A=1;LS138B=1;LS138C=0;break;
case4:
LS138A=0;LS138B=0;LS138C=1;break;
case5:
LS138A=1;LS138B=0;LS138C=1;break;
case6:
LS138A=0;LS138B=1;LS138C=1;break;
case7:
LS138A=1;LS138B=1;LS138C=1;break;
}
delay(50);
}
}
/***************************************************************************************
延时程序*
****************************************************************************************/
voiddelay(unsignedinti)
{
charj;
for(i;i>0;i--)
for(j=200;j>0;j--);
}
/*****************************************************************************