您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > PS2键盘C语言资料
PS2键盘编程详细资料0推荐在单片机系统中,经常使用的键盘都是专用键盘.此类键盘为单独设计制作的,成本高、使用硬件连接线多,且可靠性不高,这一状况在那些要求键盘按键较多的应用系统中更为突出.与此相比,在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;//将时钟线拉低并保持100usdelay100us();PS2_SGN_DATA=0;//起始位PS2_SGN_CLOCK=1;//发送DATA0-7for(sentbit_cnt=0;sentbit_cnt8;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;//发送停止位,停止位总为1while(!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;//关外部中断0switch(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多媒体按键键盘时,只需要将键表中相应处修改即可,如ACPIPower按键通码为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;//capslockelseled_status|=0x04;ps2_ledchange();break;case0x59:agcs_status&=0xEF;break;//右shift释放case0x7
本文标题:PS2键盘C语言资料
链接地址:https://www.777doc.com/doc-2853003 .html