lizhirui 发表于 2014-12-10 13:03

原创——20140812PS2键盘程序

这个程序是我当时写的,现在发出来
本程序基于STC12C5608AD,该程序实现了判定特殊按键,并且最终返回一系列数值,支持锁定键以及键盘灯主机发送数据到键盘:
1) 把时钟线拉低至少100微秒2) 把数据线拉低3) 释放时钟线4) 等待设备把时钟线拉低5) 设置/复位数据线发送第一个数据位6) 等待设备把时钟拉高7) 等待设备把时钟拉低8) 重复 5-7步发送剩下的7 个数据位和校验位9) 释放数据线10) 等待设备把数据线拉低11) 等待设备把时钟线拉低12) 等待设备释放数据线和时钟线PS2向主机:
1) 检测时钟线电平,如果时钟线为低,则延时50μs;2) 检测判断时钟信号是否为高,为高,则向下执行,为低,则转到(1);3) 检测数据线是否为高,如果为高则继续执行,如果为低,则放弃发送(此时PC机在向PS2设备发送数据,所以PS2设备要转移到接收程序处接收数据);4) 延时20μs(如果此时正在发送起始位,则应延时40μs);5) 输出起始位(0)到数据线上。这里要注意的是:在送出每一位后都要检测时钟线,以确保PC机没有抑制PS2设备,如果有则中止发送;6) 输出8个数据位到数据线上;7) 输出校验位;8) 输出停止位(1);9) 延时30μs(如果在发送停止位时释放时钟信号则应延时50μs); 按如下的过程发送单个位1) 设置/复位数据2) 延迟20 微秒3) 把时钟拉低4) 延迟40 微秒5) 释放时钟6) 延迟20 微秒
PS2通信数据帧格式:

1个起始位总是逻辑0
8个数据位(LSB)低位在前
1个奇偶校验位奇校验
1个停止位总是逻辑1
1个应答位仅用在主机对设备的通讯中

主机向键盘的命令集:● 0xFF (Reset)——引起键盘进入Reset 模式(见复位部分)。● 0xFE (Resend)——用于只是在接收中出现的错误。键盘的响应就是重发送最后的扫描码或者命令回应给主机。但是0xFE绝不会作为Resend命令的回应而被发送。● *0xFD (Set Key Type Make)——允许主机指定一个按键只发送通码。这个按键不发送断码或进行机打重复。指定的按键采用它的第三套扫描码。● *0xFC (Set Key Type Make/Break)——类似于Set Key Type Make,只有通码和断码是使能的(机打被禁止了)。● *0xFB (Set Key Type Typematic)——类似于前两条命令通码和机打是使能的,而断码被禁止。● *0xFA (Set All Keys Typematic/Make/Break)——缺省设置所有键的通码、断码和机打重复都使能(除了Print Screen 键,它在第一套和第二套中没有断码)。● *0xF9 (Set All Keys Make)——所有键都只发送通码;断码和机打重复被禁止。● *0xF8 (Set All Keys Make/Break)——类似于前两条命令,除了机打重复被禁止外。● *0xF7 (Set All Keys Typematic)——类似于前三条命令仅断码被禁止,通码和机打重复是使能的。● 0xF6 (Set Default)——载入缺省的机打速率/延时(10.9cps/500ms),按键类型(所有按键都使能机打/通码/断码),以及第二套扫描码集。● 0xF5 (Disable)——键盘停止扫描,载入缺省值键Set Default 命令,等待进一步指令。● 0xF4 (Enable)——在用上一条命令禁止键盘后,重新使能键盘。● 0xF3 (Set Typematic Rate/Delay)——主机在这条命令后会发送一个字节的参数来定义机打速率和延时,具体含义如表2.1、2.2所示。表2.1Repeat Rate
Bits0-4Rate(cps)Bits0-4Rate(cps)Bits0-4Rate(cps)Bits0-4Rate(cps)
00h2.008h4.010h8.018h16.0
01h2.109h4.311h8.619h17.1
02h2.30Ah4.612h9.21Ah18.5
03h2.50Bh5.013h10.01Bh20.0
04h2.70Ch5.514h10.91Ch21.8
05h3.00Dh6.015h12.01Dh24.0
06h3.30Eh6.716h13.31Eh26.7
07h3.70Fh7.517h15.01Fh30.0
表2.2Delay
Bits5-6Delay(seconds)
00b0.25
01b0.50
10b0.75
11b1.00
● *0xF2 (Read ID)——键盘回应两个字节的设备ID,0xAB、0x83。● *0xF0 (Set Scan Code Set)——主机在这个命令后发送一个字节的参数,是定键盘使用哪套扫描码集。参数字节可以是0x01、0x02或0x03分别选择扫描码集第一套、第二套或第三套。如果要获得当前正在使用的扫描码集,只要发送带0x00参数的本命令即可。● 0xEE (Echo)——键盘用“Echo”0xEE 回应。● 0xED (Set/Reset LEDs)——主机在本命令后跟随一个参数字节,用于指示键盘上Num Lock, Caps Lock,and Scroll Lock LED的状态这个参数字节的定义如下:MSB                                                                        LSB
Always0Always0Always0Always0Always0Caps LockNum LockScroll Lock
○"Scroll Lock" - Scroll Lock LED off(0)/on(1)○"Num Lock" - Num Lock LED off(0)/on(1)○"Caps Lock" - Caps Lock LED off(0)/on(1) *只是最初可用于PS/2 键盘。
程序如下:
#include "common.h"
#include "uart.h"
#define WAITTIME 10000
bit ext=0;
bit up=0;
bit shift=0,ctrl=0,alt=0,gui=0,lshift=0,lctrl=0,lalt=0,lgui=0,numlock=1,capslock=0,scrolllock=0;
sbit CLK=P1^6;
sbit DAT=P1^7;
unsigned char code UnShifted = {
0x1C, 'a',
0x32, 'b',
0x21, 'c',
0x23, 'd',
0x24, 'e',
0x2B, 'f',
0x34, 'g',
0x33, 'h',
0x43, 'i',
0x3B, 'j',
0x42, 'k',
0x4B, 'l',
0x3A, 'm',
0x31, 'n',
0x44, 'o',
0x4D, 'p',
0x15, 'q',
0x2D, 'r',
0x1B, 's',
0x2C, 't',
0x3C, 'u',
0x2A, 'v',
0x1D, 'w',
0x22, 'x',
0x35, 'y',
0x1A, 'z',
0x45, '0',
0x16, '1',
0x1E, '2',
0x26, '3',
0x25, '4',
0x2E, '5',
0x36, '6',
0x3D, '7',
0x3E, '8',
0x46, '9',
0x0E, '`',
0x4E, '-',
0x55, '=',
0x5D, '\\',
0x29, ' ',
0x54, '[',
0x5B, ']',
0x4C, ';',
0x52, '\'',
0x41, ',',
0x49, '.',
0x4A, '/',
0x71, '.',
0x70, '0',
0x69, '1',
0x72, '2',
0x7A, '3',
0x6B, '4',
0x73, '5',
0x74, '6',
0x6C, '7',
0x75, '8',
0x7D, '9',
0x66, ' ',
0x5A, ' ',
};
unsigned char code Shifted = {
0x1C, 'A',
0x32, 'B',
0x21, 'C',
0x23, 'D',
0x24, 'E',
0x2B, 'F',
0x34, 'G',
0x33, 'H',
0x43, 'I',
0x3B, 'J',
0x42, 'K',
0x4B, 'L',
0x3A, 'M',
0x31, 'N',
0x44, 'O',
0x4D, 'P',
0x15, 'Q',
0x2D, 'R',
0x1B, 'S',
0x2C, 'T',
0x3C, 'U',
0x2A, 'V',
0x1D, 'W',
0x22, 'X',
0x35, 'Y',
0x1A, 'Z',
0x45, '0',
0x16, '1',
0x1E, '2',
0x26, '3',
0x25, '4',
0x2E, '5',
0x36, '6',
0x3D, '7',
0x3E, '8',
0x46, '9',
0x0E, '~',
0x4E, '_',
0x55, '+',
0x5D, '|',
0x29, ' ',
0x54, '{',
0x5B, '}',
0x4C, ':',
0x52, '"',
0x41, '<',
0x49, '>',
0x4A, '?',
0x71, '.',
0x70, '0',
0x69, '1',
0x72, '2',
0x7A, '3',
0x6B, '4',
0x73, '5',
0x74, '6',
0x6C, '7',
0x75, '8',
0x7D, '9',
0x66, ' ',
0x5A, ' ',
};
void SendPS2(uchar dat)
{
uchar i=0;
bit chk=1;
CLK=0;
Delay(1);
DAT=0;
CLK=1;
while(CLK);
for(i=0;i<8;i++)
{
DAT=(dat>>i)&0x01;
if(((dat>>i)&0x01)==1)
{
chk=~chk;
}
while(!CLK);
while(CLK);
}
DAT=chk;
while(!CLK);
while(CLK);
DAT=1;
while(DAT);
while(CLK);
while((!DAT)||(!CLK));
}
uchar ReadPS2() reentrant
{
uchar result=0,i=0;
if(!CLK)
{
while(!CLK);//等待起始位发送完毕
for(i=0;i<8;i++)//LSB
{
while(CLK);//等待时钟线
result|=((uchar)(DAT)<<i);
while(!CLK);//等待释放时钟线
}
while(CLK);
while(!CLK);//校验位
while(CLK);
while(!CLK);//停止位
if(result==0xE0||result==0xE1)
{
ext=1;
while(CLK);
return ReadPS2();
}
else if(result==0xF0)
{
up=1;
while(CLK);
return ReadPS2();
}
return result;
}
return 0x00;
}
bit IsKey(bit e,bit u,uchar key,uchar key2)
{
return (e==ext)&&(u==up)&&(key==key2);
}
void SetKeyLed(uchar num,uchar caps,uchar scroll)
{
    SendPS2(0xED);
SendPS2(scroll|(num<<1)|(caps<<2));
Delay(10000);
}
void ClearControlKey()
{
ctrl=0;
alt=0;
shift=0;
gui=0;
lctrl=0;
lalt=0;
lshift=0;
lgui=0;
}
bit SetControlKey(uchar key)
{
if(IsKey(0,0,0x12,key))//L Shift
{
shift=1;
lshift=1;
}
else if(IsKey(0,1,0x12,key))//L Shift Up
{
shift=0;
lshift=0;
}
else if(IsKey(0,0,0x14,key))//L Ctrl
{
ctrl=1;
lctrl=1;
}
else if(IsKey(0,1,0x14,key))//L Ctrl Up
{
ctrl=0;
lctrl=0;
}
else if(IsKey(0,0,0x11,key))//L Alt
{
alt=1;
lalt=1;
}
else if(IsKey(0,1,0x11,key))//L Alt Up
{
alt=0;
lalt=0;
}
else if(IsKey(1,0,0x1F,key))//L GUI
{
gui=1;
lgui=1;
}
else if(IsKey(1,1,0x1F,key))//L GUI Up
{
gui=0;
lgui=0;
}
else if(IsKey(0,0,0x59,key))//R Shift
{
shift=1;
lshift=0;
}
else if(IsKey(0,1,0x59,key))//R Shift Up
{
shift=0;
lshift=0;
}
else if(IsKey(1,0,0x14,key))//R Ctrl
{
ctrl=1;
lctrl=0;
}
else if(IsKey(1,1,0x14,key))//R Ctrl Up
{
ctrl=0;
lctrl=0;
}
else if(IsKey(1,0,0x11,key))//R Alt
{
alt=1;
lalt=0;
}
else if(IsKey(1,1,0x11,key))//R Alt Up
{
alt=0;
lalt=0;
}
else if(IsKey(1,0,0x27,key))//R GUI
{
gui=1;
lgui=0;
}
else if(IsKey(1,1,0x27,key))//R GUI Up
{
gui=0;
lgui=0;
}
else if(IsKey(0,0,0x77,key))//NumLock
{
numlock=~numlock;
SetKeyLed(numlock,capslock,scrolllock);
ClearControlKey();
}
else if(IsKey(0,1,0x77,key))//NumLock Up
{
ClearControlKey();
}
else if(IsKey(0,0,0x58,key))//CapsLock
{
capslock=~capslock;
SetKeyLed(numlock,capslock,scrolllock);
ClearControlKey();
}
else if(IsKey(0,1,0x58,key))//CapsLock Up
{
ClearControlKey();
}
else if(IsKey(0,0,0x7E,key))//ScrollLock
{
scrolllock=~scrolllock;
SetKeyLed(numlock,capslock,scrolllock);
ClearControlKey();
}
else if(IsKey(0,1,0x7E,key))//ScrollLock Up
{
ClearControlKey();
}
else
{
return 0;
}
return 1;
}
void ResetKey()
{
SendPS2(0xFF);
Delay(20000);
}
uchar GetChar(uchar key,bit s)
{
uchar i=0;
if(s)
{
for(i=0;i<61;i++)
{
if(Shifted==key)
{
return Shifted;
}
}
}
else
{
for(i=0;i<61;i++)
{
if(UnShifted==key)
{
return UnShifted;
}
}
}
return 0x00;
}
void main()
{
uchar key=0,tmp=0;
Uart_Init();
CLK=1;
DAT=1;
Delay(10000);
ResetKey();
SetKeyLed(numlock,capslock,scrolllock);
while(1)
{
ext=0;
up=0;
key=ReadPS2();
if((key!=0x00)&&!SetControlKey(key))
{
SendData((uchar)lgui<<7|(uchar)lalt<<6|(uchar)lshift<<5|(uchar)lctrl<<4|(uchar)gui<<3|(uchar)alt<<2|(uchar)shift<<1|(uchar)ctrl);
SendData((uchar)ext|(uchar)up<<1|(uchar)numlock<<2|(uchar)capslock<<3|(uchar)scrolllock<<4);
SendData(key);
}
}
}



f378694339 发表于 2014-12-10 13:10

感谢分享 支持了 楼主{:301_993:}

GA゛木子 发表于 2014-12-10 16:59

完全看不懂+_+都晕掉了

pppszxc 发表于 2014-12-12 11:21

感觉像单片机的程序

lizhirui 发表于 2014-12-12 17:27

就是单片机程序

284912933 发表于 2014-12-12 18:29

完全看不懂啊,只知道是和键盘有关的东西....{:1_906:}
页: [1]
查看完整版本: 原创——20140812PS2键盘程序