在单片机系统中,经常使用的键盘都是专用键盘.此类键盘为单独设计制作的,成本高、使用硬件连接线多,且可靠性不高,这一状况在那些要求键盘按键较多的应用系统中更为突出.与此相比,在PC系统中广泛使用PS/2键盘具有价格低、通用可靠,且使用连接线少(仅使用2根信号线)的特点,并可满足多种系统的要求.因此在单片机系统中应用PS/2键盘是一种很好的选择.
文中在介绍PS/2协议和PS/2键盘工作原理与特点的基础上,给出了一个在单片机上实现对PS/2键盘支持的硬件连接与驱动程序设计实现.该
设计实现了在单片机系统中对PS/2标准104键盘按键输入的支持.使用Keil C51开发的驱动程序接口和库函数可以方便地移植到其他单片机或嵌入式系统中.所有程序在Keil uVision2上编译通过,在单片机AT89C51上测试通过.
1 PS/2协议
目前,PC机广泛采用的PS/2接口为mini-DIN 6pin的连接器,如图1所示.
PS/2设备有主从之分,主设备采用Female插座,从设备采用Male插头.现在广泛使用的PS/2键盘鼠标均在从设备方式下工作.PS/2接口的时钟
与数据线都是集电极开路结构,必须外接上拉电阻(一般上拉电阻设置在主设备中).主从设备之间数据通信采用双向同步串行方式传输,时钟信号由从设备产生.
1.1 从设备到主设备的通信
当从设备向主设备发送数据时,首先检查时钟线,以确认时钟线是否为高电平.如果是高电平,从设备就可以开始传输数据;反之,从设备要等待获得总线的控制权,才能开始传输数据.传输的每一帧由11位组成,发送时序及每一位的含义如图2所示.
每一帧数据中开始位总是为0,数据校验采用奇校验方式,停止位始终为1.从设备到主设备通信时,从设备总是在时钟线为高时改变数据线状态,主设备在时钟下降沿读人数据线状态.
1.2 主设备到从设备的通信
主设备与从设备进行通信时,主设备首先将时钟线和数据线设置为“请求发送”状态,具体方式为:首先下拉时钟线至少100us抑制通信,然后下拉数据线“请求发送”,最后释放时钟线.在此过程中,从设备在不超过10us的间隔内必须检查这个状态,当设备检测到这个状态时,它将开始产生时钟信号.此时数据传输的每一帧由12位构成,其时序和每一位含义如图3所示.
与从设备到主设备通信相比,其每帧数据多了一个ACK位.这是从设备应答接收到字节的应答位,由从设备通过拉低数据线产生,应答位ACK总
是为0.主设备到从设备通信过程中,主设备总是在时钟线为低电平时改变数据线的状态,从设备在时钟上升沿读人数据线状态.
2 PS/2键盘的编码与命令集
2.1 PS/2键盘的编码
目前,PC机使用的PS/2键盘都默认采用第2套扫描码集.扫描码有两种不同的类型:“通码(make code)”和“断码(break code)”.当一个键被按下或持续按住时,键盘会将该键的通码发送给主机;而当一个键被释放时,键盘会将该键的断码发送给主机.根据键盘按键扫描码的不同,可将按键分为3类:
第1类按键 通码为一个字节,断码为0xF0+通码形式.如A键,其通码为0x1C;断码为0xF0 0x1C.
第2类按键 通码为两字节0xE0+0xXX形式,断码为0xE0+0xF0+0xXX形式.如Right Ctrl键,其通码为0xE0 0x14;断码为0xE0 0xF0 0x14.
第3类特殊按键 有两个,Print Screen键,其通码为0xE0 0x12 0xE0 0x7C;断码为0xE0 0xF0 0x7C 0xE0 0xF0 0x12.Pause键,其通码为0xE1 0x14 0x77 0xE1 0xF0 0xl4 0xF0 0x77;断码为空.
组合按键扫描码的发送是按照按键发生的次序,如按下面顺序按左Shift十A键:① 按下左Shift键;② 按下A键;③ 释放A键;④ 释放左Shift键,那么计算机上接收到的一串数据为0x12 0x1C 0xF0 0x1C 0xF0 0x12.
在文中的驱动程序设计中,就是根据按键的分类对其分别进行处理.
2.2 PS/2键盘的命令集
主机可通过向PS/2键盘发送命令对键盘进行设置或者获得键盘的状态等操作.每发送一个字节,主机都会从键盘获得一个应答0xFA(“重发
resend”和“回应echo”命令例外).驱动程序在键盘初始化过程中所用的指令:0xED,主机在该命令后跟随发送一个参数字节,用于指示键盘上Num Lock,Caps Lock,Scroll Lock Led的状态;0xF3,主机在这条命令后跟随发送一个字节参数定义键盘机打的速率和延时;0xF4,用于当主机发送0xF5禁止键盘后,重新使能键盘.
3 PS/2键盘与单片机的连接电路
PS/2键盘与AT89C51单片机的连接方式如图4所示.P1.0接PS/2数据线;P3.2(INT0)接PS/2时钟线.因为单片机的P1,P3口内部是带上拉电阻的,所以PS/2的时钟线和数据线可以直接与单片机的P1,P3相连接.
4 驱动程序设计
驱动程序的开发使用Keil C51语言以及KeiluVision2编程环境.PS/2 104键盘驱动程序主要任务是实现单片机与键盘间PS/2通信,同时将接收到的按键扫描码转换为该按键的键值KeyVal,提供给系统上层软件使用.
4.1 单片机与键盘间PS/2通信的程序设计
在PS/2通信过程中,主设备(文中是单片机)是在时钟信号为低时发送和接收数据信号.因为单片机向键盘发送的是指令,需要键盘回应,所以这
部分程序采用查询方式;而单片机接收键盘数据时,数据线上的信号在时钟为低时已经稳定,所以这部分程序采用中断方式,且不需要在程序中加入延时程序.
单片机向PS/2键盘发送数据程序代码为:
- void ps2_sentchar(unsigned char sentchar){//ps2主设备向从设备发送数据
- unsigned char sentbit_cnt= 0x00;
- unsigned char sentchar_chk = 0x00;
- EX0=0; //关外部中断0
- //发起一个传送,发起始位
- PS2_SGN_CLOCK = 0; //将时钟线拉低并保持100 us
- 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)
- {
- case 0:
- case 2:
- case 4:
- case 6:PS2_SGN_DATA =1;break;//奇校验
- case 1:
- case 3:
- case 5:
- case 7: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
- }