MiPS2键盘编程详细资料.docx
《MiPS2键盘编程详细资料.docx》由会员分享,可在线阅读,更多相关《MiPS2键盘编程详细资料.docx(17页珍藏版)》请在冰点文库上搜索。
MiPS2键盘编程详细资料
PS2键盘编程详细资料
在单片机系统中,经常使用的键盘都是专用键盘.此类键盘为单独设计制作的,成本高、使用硬件连接线多,且可靠性不高,这一状况在那些要求键盘按键较多的应用系统中更为突出.与此相比,在PC系统中广泛使用PS/2键盘具有价格低、通用可靠,且使用连接线少(仅使用2根信号线)的特点,并可满足多种系统的要求.因此在单片机系统中应用PS/2键盘是一种很好的选择.
文中在介绍PS/2协议和PS/2键盘工作原理与特点的基础上,给出了一个在单片机上实现对PS/2键盘支持的硬件连接与驱动程序设计实现.该设计实现了在单片机系统中对PS/2标准104键盘按键输入的支持.使用KeilC51开发的驱动程序接口和库函数可以方便地移植到其他单片机或嵌入式系统中.所有程序在KeiluVision2上编译通过,在单片机AT89C51上测试通过.
1PS/2协议
目前,PC机广泛采用的PS/2接口为mini-DIN6pin的连接器,如图1所示.
PS/2设备有主从之分,主设备采用Female插座,从设备采用Male插头.现在广泛使用的PS/2键盘鼠标均在从设备方式下工作.PS/2接口的时钟
与数据线都是集电极开路结构,必须外接上拉电阻(一般上拉电阻设置在主设备中).主从设备之间数据通信采用双向同步串行方式传输,时钟信号由从设备产生.
1.1从设备到主设备的通信
当从设备向主设备发送数据时,首先检查时钟线,以确认时钟线是否为高电平.如果是高电平,从设备就可以开始传输数据;反之,从设备要等待获得总线的控制权,才能开始传输数据.传输的每一帧由11位组成,发送时序及每一位的含义如图2所示.
每一帧数据中开始位总是为0,数据校验采用奇校验方式,停止位始终为1.从设备到主设备通信时,从设备总是在时钟线为高时改变数据线状态,主设备在时钟下降沿读人数据线状态.
1.2主设备到从设备的通信
主设备与从设备进行通信时,主设备首先将时钟线和数据线设置为“请求发送”状态,具体方式为:
首先下拉时钟线至少100us抑制通信,然后下拉数据线“请求发送”,最后释放时钟线.在此过程中,从设备在不超过10us的间隔内必须检查这个状态,当设备检测到这个状态时,它将开始产生时钟信号.此时数据传输的每一帧由12位构成,其时序和每一位含义如图3所示.
与从设备到主设备通信相比,其每帧数据多了一个ACK位.这是从设备应答接收到字节的应答位,由从设备通过拉低数据线产生,应答位ACK总是为0.主设备到从设备通信过程中,主设备总是在时钟线为低电平时改变数据线的状态,从设备在时钟上升沿读人数据线状态.
2PS/2键盘的编码与命令集
2.1PS/2键盘的编码
目前,PC机使用的PS/2键盘都默认采用第2套扫描码集.扫描码有两种不同的类型:
“通码(makecode)”和“断码(breakcode)”.当一个键被按下或持续按住时,键盘会将该键的通码发送给主机;而当一个键被释放时,键盘会将该键的断码发送给主机.根据键盘按键扫描码的不同,可将按键分为3类:
第1类按键通码为一个字节,断码为0xF0+通码形式.如A键,其通码为0x1C;断码为0xF00x1C.
第2类按键通码为两字节0xE0+0xXX形式,断码为0xE0+0xF0+0xXX形式.如RightCtrl键,其通码为0xE00x14;断码为0xE00xF00x14.
第3类特殊按键有两个,PrintScreen键,其通码为0xE00x120xE00x7C;断码为0xE00xF00x7C0xE00xF00x12.Pause键,其通码为0xE10x140x770xE10xF00xl40xF00x77;断码为空.
组合按键扫描码的发送是按照按键发生的次序,如按下面顺序按左Shift十A键:
①按下左Shift键;②按下A键;③释放A键;④释放左Shift键,那么计算机上接收到的一串数据为0x120x1C0xF00x1C0xF00x12.
在文中的驱动程序设计中,就是根据按键的分类对其分别进行处理.
2.2PS/2键盘的命令集
主机可通过向PS/2键盘发送命令对键盘进行设置或者获得键盘的状态等操作.每发送一个字节,主机都会从键盘获得一个应答0xFA(“重发resend”和“回应echo”命令例外).驱动程序在键盘初始化过程中所用的指令:
0xED,主机在该命令后跟随发送一个参数字节,用于指示键盘上NumLock,CapsLock,ScrollLockLed的状态;0xF3,主机在这条命令后跟随发送一个字节参数定义键盘机打的速率和延时;0xF4,用于当主机发送0xF5禁止键盘后,重新使能键盘.
3PS/2键盘与单片机的连接电路
PS/2键盘与AT89C51单片机的连接方式如图4所示.P1.0接PS/2数据线;P3.2(INT0)接PS/2时钟线.因为单片机的P1,P3口内部是带上拉电阻的,所以PS/2的时钟线和数据线可以直接与单片机的P1,P3相连接.
4驱动程序设计
驱动程序的开发使用KeilC51语言以及KeiluVision2编程环境.PS/2104键盘驱动程序主要任务是实现单片机与键盘间PS/2通信,同时将接收到的按键扫描码转换为该按键的键值KeyVal,提供给系统上层软件使用.
4.1单片机与键盘间PS/2通信的程序设计
在PS/2通信过程中,主设备(文中是单片机)是在时钟信号为低时发送和接收数据信号.因为单片机向键盘发送的是指令,需要键盘回应,所以这部分程序采用查询方式;而单片机接收键盘数据时,数据线上的信号在时钟为低时已经稳定,所以这部分程序采用中断方式,且不需要在程序中加入延时程序.
单片机向PS/2键盘发送数据程序代码为:
voidps2_sentchar(unsignedcharsentchar){//ps2主设备向从设备发送数据
unsignedcharsentbit_cnt=0x00;
unsignedcharsentchar_chk=0x00;
EX0=0;//关外部中断0
//发起一个传送,发起始位
PS2_SGN_CLOCK=0;//将时钟线拉低并保持100us
delay100us();
PS2_SGN_DATA=0;//起始位
PS2_SGN_CLOCK=1;
//发送DATA0-7
for(sentbit_cnt=0;sentbit_cnt<8;sentbit_cnt++){
while(PS2_SGN_CLOCK)_nop_();//等待时钟线变为低
PS2_SGN_DATA=sentchar&0x01;//发送数据
if(PS2_SGN_DATA)sentchar_chk++;//计算校验
while(!
PS2_SGN_CL0CK)_nop_();//等待时钟线变高
sentchar>>=1;//待发送数据右移一位
}
//发送校验位
while(PS2_SGN_CLOCK)_nop_();//等待时钟线变低
switch(sentchar_chk){
case0:
case2:
case4:
case6:
PS2_SGN_DATA=1;break;//奇校验
case1:
case3:
case5:
case7:
PS2_SGN_DATA=0;break;//奇校验
default;break;
)
while(!
PS2_SGN_CLOCK)_nop_();//等待时钟线变高
while(PS2_SGN_CLOCK)_nop_();//等待时钟线变低
PS2_SGN_DATA=1;//发送停止位,停止位总为1
while(!
PS2_SGN_CLOCK)_nop_();//等待时钟线变高
while(PS2_SGN_CLOCK)_nop_();//等待时钟线变低
//接收ACK
//if(PS2_SGN_DATA)error();
//ACK信号由键盘发出,总为低电平
while(!
PS2_SGN_CLOCK)_nop_();//等待时钟线变高
EX0=1;//开外部中断0
}
单片机由PS/2键盘接收数据程序:
外部中断0设置为下降沿触发
voidint0()interrupt0using0{//
EX0=0;//关外部中断0
switch(ps2_revchar_cnt){
case1:
……
case8:
mcu_revchar<<=1;
if(PS2_SGN_DATA)mcu_revchar|=0x01;
ps2_revchar_cnt++;
break;
case0:
ps2_revchar_cnt++;break;//开始位,
case9:
ps2_revchar_cnt++;break;//校验位,可添加校验程序
case10:
_nop_();//停止位
ps2_revchar_cnt=0;
revchar_flag=1;//置接收到数据标识位
break;
default:
break;
}
EX0=1;//开外部中断0
}
4.2键盘扫描码转换程序设计
由于键盘扫描码无规律可循,因此由键盘扫描码获得相应按键的键值(字符键为其ASCII值,控制键如F1,Ctrl等为自定义值),只能通过查表的方式获得.由于按键的3种类型及部分按键对应着两个键值(如A键的键值根据Caps和Shift键状态有0x41(A)和0x61(a)两种),因此综合考虑查表转换速度和资源消耗,设计中使用4个键盘表:
键盘扫描码转换基本集和切换集(kb_plain_map[NR_KEYS]与kb_shift_map[NR_KEYS]);包含E0前缀的键盘扫描码转换基本集和切换集(kbeO_plain_map[NR_KEYS]与kbe0_shiftmap[NR_KEYS]).PS/2104键盘按键扫描码最大值为0x83,所以设置NR_KEYS为132.所有4个键盘表的定义均为如下形式:
KB_MAP[MAKECODE]=KEYVAL,如果扫描码对应的按键为空(如KB_MAP[0x00]),则定义相应键值为NULL_KEY(0x00).以下是键盘扫描码基本集的部分代码实例:
kb_plain_map[NR_KEYS]={……
NULL_KEY;0x2C;0x6B;0x69;0x6F;0x30;0x39;
NULL_KEY;//扫描码0x40~0x47
//对应按键空,逗号,K,I,O,0,9,空
//对应键值0x00,',','k','i','o','O','9',0x00……};
如此设计键盘转换表的另一个好处在于,以后如需扩展支持有ACPI、Windows多媒体按键键盘时,只需要将键表中相应处修改即可,如ACPI
Power按键通码为0xE00x37,修改kbe0_plain_map[0x37]=KB_ACPI_PWR即可.
特殊按键Pause使用单独程序处理,如果接收到0xE1就转入这段程序.而PrintScreen键则将其看作是两个通码分别为0xE00x12和0xE00x7C
的“虚键”的组合键处理.在驱动程序中设定如下全局变量:
led_status记录ScrollLockLed,NumLockLed和CapsLockLed的状态(关为0,开为1);agcs_status记录左右ShiftCtrlGuiAlt状态,相应键按下则对应位为1,释放为0.E0_FLAG接到0xE0置1;E1_FLAG接收到0xE1置1;F0_FLAG接收到0xF0置1.按键键值通过KeyVal提供上层程序使用.PS/2键盘扫描码键值转换程序ps2_codetrans()流程框架如图5所示.
第1类按键的扫描码键值转换程序代码。
if(F0_FLAG){//接收扫描码为断码
switch(mcu_revchar){//处理控制键
case0x11:
ages_status&=0xF7;break;//左alt释放
case0x12:
ages_status&=0xFE;break;//左shift释放
case0x14:
agcs_status&=0xFD;break;//左ctrl释放
case0x58;if(led_status&0x04)led_status&=0x03;//capslock
elseled_status|=0x04;
ps2_ledchange();
break;
case0x59:
agcs_status&=0xEF;break;//右shift释放
case0x77:
if(led_status&0x02)led_status&=0x05;//numlock
elseled_status|=0x02;
ps2_ledchange();
break;
case0x7E:
if(led_status&0x01)led_status&=0x06;//scrolllock
elseled_status|=0x01;
ps2_ledchange();
break;
default;break;
}
F0_FLAG=0;
}
else{//接收扫描码为通码
if(led_status&0x04)caps_flag=1;elsecaps_flag=0;
if(led_status&0x02)num_flag=1;elsenum_flag=0;
if(agcs_status&0x11)shift_flag=1;else
shift_flag=0;
//扫描码键值转换
if((caps_flag==shift_flag)||(!
num_flag))KeyVal=kb_plain_map[mcu_revchar];
elseKeyVal=kb_shift_map[mcu_revchar];
switch(mcu_revchar)(//处理控制键或状态键
case0x11:
agcs_status|=0x08;//左alt按下
Case0x12:
agcs_status|=0x01;//左shift按下
case0x14:
agcs_status|=0x02;//左ctrl按下
case0x59:
agcs_status|=0x10;//右shift按下
default:
break;
}
}
第2类按键的扫描码键值转换程序与上面相似.注意:
在退出该程序段时,对E0_FLAG和F0_FLAG标识清0.Pause键的处理程序,如果接收到0xE1,置E1_FLAG=1,然后顺次将后续接收到的7个字节数据和Pause的通码后7个字节比较,一致则返回KeyVal=KB_PAUSE;在比较完所有7个字节后清除E1_FLAG标识.键盘初始化程序kb_init()流程为:
①上电后,接收键盘上电自检通过信号0xAA,或者自检出错信号0xFC.单片机接收为0xAA则进入下一步,否则进行出错处理.
②关LED指示,单片机发送0xED,然后接收键盘回应0xFA,接着发送0x00接收0xFA.
③设置机打延时和速率:
单片机发送0xF3,接收0xFA,发送0x00(250ms,2.0cps),接收0xFA.
④检查LED,发送0xED,接收0xFA,发送0x07(开所有LED),接收0xFA.发送0xED,接收0xFA,发送0x00(关LED),接收0xFA.
⑤允许键盘,发送0xF4,接收0xFA.键盘LED改变ps2_ledchange()函数流程:
发送0xED;接收0xFA;发送led_status;接收0xFA.
5结语
该驱动程序经KeiluVision2编译,在AT89C51单片机上运行通过,实现了对PS/2104键盘的支持,实现了对字符按键大小写切换,NumLock切换、控制键及组合按键的支持.同时该程序对其他嵌入式或单片机系统中PS/2键盘的应用也有借鉴意义
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的个数总为奇数,因此总进行奇校验。
三.PS/2发送数据到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)释放数据线。
四.键盘返回值介绍:
注意:
键盘的返回值并不是和一般ASCII码相对应!
键盘的处理器如果发现有键被按下释放或按住键盘将发送扫描码的信息包到计算机扫描码有两种不同的类型通码和断码当一个键被按下或按住就发送通码当一个键被释放就发送断码每个按键被分配了唯一的通码和断码这样主机通过查找唯一的扫描码就可以测定是哪个按键每个键一整套的通断码组成了扫描码集有三套标准的扫描码集分别是第一套第二套和第三套所有现代的键盘默认使用第二套扫描码
虽然多数第二套通码都只有一个字节宽但也有少数扩展按键的通码是两字节或四字节宽这类的通码第一个字节总是为E0h
正如键按下通码就被发往计算机一样只要键一释放断码就会被发送每个键都有它自己唯一的通码它们也都有唯一的断码幸运的是你不用总是通过查表来找出按键的断码在通码和断码之间存在着必然的联系多数第二套断码有两字节长它们的第一个字节是F0h第二个字节是这个键的通码扩展按键的断码通常有三个字节它们前两个字节是E0h,F0h最后一个字节是这个按键通码的最后一个字节作为一个例子我在下面列出了几个按键的第二套通码和断码
No.
KEY
通码(第二套)
断码(第二套)
1
"A"
1C
F01C
2
"5"
2E
F02E
3
"F10"
09
F009
4
RightArrow
E0 74
E0F074
5
Right"Ctrl"
E014
E0F014
一个键盘发送值的例子:
通码和断码是以什么样的序列发送到你的计算机从而使得字符G出现在你的字处理软件里的呢因为这是一个大写字母需要发生这样的事件次序按下Shift键按下G键释放G键释放Shift键与这些时间相关的扫描码如下Shift键的通码12hG键的通码34hG键的断码F0h34hShift键的断码F0h12h因此发送到你的计算机的数据应该是
12h34hF0h34hF0h12h
五:
第二套扫描码:
101102和104键的键盘:
KEY
通码
断码
KEY
通码
断码
KEY
通码
断码
A
1C
F01C
9
46
F046
[
54
F054
B
32
F032
`
0E
F00E
INSERT
E070
E0 F070
C