根据客户的要求利用单片机制作一个小的工控键盘,将下面对应的键值发送到电脑显示,利用的协议就是PS2,单片机型号为stc89c52rc,晶振为12M;
1 0
6 5 4 3 2
7 8 9 减号 等号
y u i o p
q w e r t
#include #include "PS2.H"BYTE PS2RecChar=0xCC;BOOL KeyBoardFlag=FALSE;#define Key_line P0 //键盘行入口#define Key_list P2 //键盘列入口#define PS2_1 0 //16#define PS2_0 1 //45#define PS2_6 2 //36#define PS2_5 3 //2e#define PS2_4 4 //25#define PS2_3 5 //26#define PS2_2 6 //1e#define PS2_7 7 //3d#define PS2_8 8 //3e#define PS2_9 9 //46#define PS2_dec 10 //4e#define PS2_eq 11 //55#define PS2_y 12 //35#define PS2_u 13 //3c#define PS2_i 14 //43#define PS2_o 15 //44#define PS2_p 16 //4d#define PS2_q 17 //15#define PS2_w 18 //1d#define PS2_e 19 //24#define PS2_r 20 //2d#define PS2_t 21 //2c//第二套键盘码unsigned char PS2Value[22]={0x16,0x45,0x36,0x2e,0x25,0x26,0x1e,0x3d,0x3e,0x46,0x4e,0x55,0x35,0x3c, 0x43,0x44,0x4d,0x15,0x1d,0x24,0x2d,0x2c}; unsigned char Key_Press(void){unsigned temp3; unsigned char flag=0; //设定标志位 Key_line=0xe0; //将P0口低5位全部设置位0 temp3=Key_list; //读取P2口的状态,若果P2口的值temp3:(temp3&0xff)!=0xff成立,表示有键按下 if(((temp3&0xff)!=0xff)) //有键按下条件判断 { flag=1; //Key_line=0XFF; //清零键盘行端口 Key_list=0xff; //清零键盘列端口 } else flag=0; //无键按下标志 return flag;}void delay(unsigned int ms){ unsigned int i,j; for(i=ms;i>0;i--) for(j=100;j>0;j--);}unsigned char Key_Scan(void){ unsigned char temp2=0,temp3=0; //temp2用来保存行键盘数据,temp3保存列键盘数据 unsigned char temp=0,flag=0; //函数返回值temp unsigned char i=0,key=0; //i位循环控制变量,给行送数据,key保存检测键盘按下的标志位 if((key=Key_Press())!=0) //判断是否有键按下 { delay(30); if((key=Key_Press())!=0) { for(i=0x01;i!=0x20;i=i<<1) //循环控制变量,扫描5行 { Key_line=(~i); //将循环控制变量赋值行地址 temp2 =(~i); //保存行地址 //temp2=Key_line; temp3=Key_list; //读取列地址数据 switch((temp3&0xff)) //判断是那列有键按下 { case 0xfe: //第一列有键按下 switch((temp2&0xff)) //判断第一列有键按下时,对应的行按键 { case 0xfe: temp=23; //第一行有键按下 break; //该键无键盘号定义 case 0xfd: //第二行有键按下 temp=PS2_6;flag=1; //对应键值位PS2键盘的数字6,对应的键盘扫描码为0x36 break; case 0xfb: //第三行有键按下 temp=PS2_7; flag=1;//对应键值位PS2键盘的数字7,对应的键盘扫描码为0x3d break; case 0xf7: //第四行有键按下 temp=PS2_y; flag=1; //对应键值位PS2键盘的字母y,对应的键盘扫描码为0x35 break; case 0xef: //第五行有键按下 temp=PS2_q ;flag=1; //对应键值位PS2键盘的字母q,对应的键盘扫描码为0x15 break; } break; case 0xfd: switch((temp2&0xff)) // 第二列有键按下 { case 0xfe: //第一行有键按下 temp=23; //该键无键盘号定义 break; case 0xfd: //第二行有键按下 temp=PS2_5;flag=1; //对应键值位PS2键盘的数字5,对应的键盘扫描码为0x2e break; case 0xfb: //第三行有键按下 temp=PS2_8; flag=1; //对应键值位PS2键盘的数字8,对应的键盘扫描码为0x8e break; case 0xf7: //第四行有键按下 temp=PS2_u;flag=1; //对应键值位PS2键盘的字母u,对应的键盘扫描码为0x3c break; case 0xef: //第五行有键按下 temp=PS2_w ; flag=1; //对应键值位PS2键盘的字母w,对应的键盘扫描码为0x1d break; } break; case 0xfb: switch((temp2&0xff)) // 第三列有键按下 { case 0xfe: //第一行有键按下 temp=23; //该键无键盘号定义 break; case 0xfd: //第二行有键按下 temp=PS2_4; flag=1; //对应键值位PS2键盘的数字4,对应的键盘扫描码为0x25 break; case 0xfb: //第三行有键按下 temp=PS2_9; flag=1; //对应键值位PS2键盘的数字9,对应的键盘扫描码为0x46 break; case 0xf7: //第四行有键按下 temp=PS2_i; flag=1; //对应键值位PS2键盘的字母i,对应的键盘扫描码为0x43 break; case 0xef: //第五行有键按下 temp=PS2_e; flag=1; //对应键值位PS2键盘的字母e,对应的键盘扫描码为0x24 break; } break; case 0xf7: switch((temp2&0xff)) // 第四列有键按下 { case 0xfe: //第一行有键按下 temp=PS2_1; flag=1; //对应键值位PS2键盘的数字1,对应的键盘扫描码为0x16 break; case 0xfd: //第二行有键按下 temp=PS2_3; flag=1; //对应键值位PS2键盘的数字3,对应的键盘扫描码为0x26 break; case 0xfb: //第三行有键按下 temp=PS2_dec;flag=1; //对应键值位PS2键盘的减号,对应的键盘扫描码为0x4e break; case 0xf7: //第四行有键按下 temp=PS2_o; flag=1; //对应键值位PS2键盘的字母o,对应的键盘扫描码为0x44 break; case 0xef: //第五行有键按下 temp=PS2_r; flag=1; //对应键值位PS2键盘的字母r,对应的键盘扫描码为0x2d break; } break; case 0xef: switch((temp2&0xff)) // 第五列有键按下 { case 0xfe: //第一行有键按下 temp=PS2_0; flag=1; //对应键值位PS2键盘的数字0,对应的键盘扫描码为0x45 break; case 0xfd: //第二行有键按下 temp=PS2_2; flag=1; //对应键值位PS2键盘的数字2,对应的键盘扫描码为0x1e break; case 0xfb: //第三行有键按下 temp=PS2_eq;flag=1; //对应键值位PS2键盘的等号,对应的键盘扫描码为0x55 break; case 0xf7: //第四行有键按下 temp=PS2_p;flag=1; //对应键值位PS2键盘的字母p,对应的键盘扫描码为0x4d break; case 0xef: //第五行有键按下 temp=PS2_t;flag=1; //对应键值位PS2键盘的字母t,对应的键盘扫描码为0x2c break; } break; } //P0=0XFF; //每当检测完一行时清零行端口和列端口 //P2=0xff; if((key=Key_Press())!=0); delay(30); } } } else temp=23; //无键按下返回数字23,对应数组内的0; if(flag==1) return temp; //返回按键扫描值 else return 23;} void OnKeyBoardOnline(BOOL i){ KeyBoardFlag=i;} //---------------------------------------------------------------------------void OnPS2ReceiveChar(BYTE ReceChar,BOOL P){ BOOL ParityBit=0; ACC=ReceChar; CY=P; ParityBit=(BOOL)(CY?0x00:0x80);//奇校验位 if(P==ParityBit); PS2RecChar=ReceChar;}//---------------------------------------------------------------------------void OnPS2SendChar(BYTE dat){ BOOL ParityBit; BYTE i; ACC=dat; CY=P; ParityBit=(BOOL)(CY?0x00:0x80);//奇校验位 CLSSIGNAL(); CT_KB=OFF; EX0=0; H_DATA=0;Delay10us();//start bit H_CLK=1; Delay10us(); H_CLK=0; Delay30us(); for(i=0;i<8;i++) { if(dat&0x01==0x01){H_DATA=1;Delay10us();} else {H_DATA=0;Delay10us();} dat>>=1; H_CLK=1; Delay10us(); H_CLK=0; Delay30us(); } H_DATA=ParityBit;Delay10us();//parity bit H_CLK=1; Delay10us(); H_CLK=0; Delay30us(); H_DATA=1;Delay10us();//stop bit H_CLK=1; Delay10us(); H_CLK=0; Delay30us(); IE0=0; EX0=1; H_CLK=1; H_DATA=1; CT_KB=ON; Delay30us();}//---------------------------------------------------------------------------void ExternInterrupt0(void) interrupt 0{ BOOL ParityBit=0,CLKFlag=1; BYTE i=0,j=8,dat=0x00; EX0=0; while(CLKFlag) { i++; if(H_CLK==1)CLKFlag=0; if(i>0xEE) { IE0=0; EX0=1; return ; } } while(j--)//延时等待大键盘的动作 { for(i=0;i<0x88;i++)//检查是否有数据处理 0x88 { if(H_CLK==0)//有动作则是大键盘存在 { OnKeyBoardOnline(TRUE);//大键盘存在,开机由大键盘应答 IE0=0; EX0=1; return ;//存在的话置标志位,并返回 } } } OnKeyBoardOnline(FALSE);//大键盘不存在,由小键盘应答 //转到接收 for(i=0;i<8;i++)//read 8bit { Delay30us(); H_CLK=0; Delay30us(); H_CLK=1; dat=dat>>1; if(H_DATA)dat|=0x80; if(H_CLK==0){ return; }//如果时钟被拉低,则有错误发生 } Delay30us(); H_CLK=0; Delay30us(); H_CLK=1; if(H_DATA)ParityBit=1; else ParityBit=0; Delay30us(); H_CLK=0; Delay30us(); H_CLK=1;//STOP BIT H_DATA 0 ERR Delay10us(); H_DATA=0; //ACK bit Delay10us(); H_CLK=0; Delay30us();Delay30us(); H_CLK=1; Delay30us(); H_DATA=1; OnPS2ReceiveChar(dat,ParityBit); IE0=0; EX0=1; return ;}//---------------------------------------------------------------------------void ProcessPS2(void){ if(KeyBoardFlag==FALSE)//大键盘不存在 { if(PS2RecChar==0xF3)//1 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0x00)//11 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0x02)//111 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0x20)//1111 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xED)//2 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xF0)//3 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xF2)//4 { OnPS2SendChar(0xFA); Delay30us(); OnPS2SendChar(0xAB); Delay30us(); OnPS2SendChar(0x83); PS2RecChar=0xCC; } else if(PS2RecChar==0xEF)//5 { OnPS2SendChar(0xFA); Delay30us(); OnPS2SendChar(0xBF); Delay30us(); OnPS2SendChar(0xB0); PS2RecChar=0xCC; } else if(PS2RecChar==0xF3)//6 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xFE)//7 //resend { PS2RecChar=0xCC; } else if(PS2RecChar==0xEE)//8 { OnPS2SendChar(0xEE); PS2RecChar=0xCC; } else if(PS2RecChar==0xEE)//9 { OnPS2SendChar(0xEE); PS2RecChar=0xCC; } else if(PS2RecChar==0xF1)//10 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xF4)//11 { OnPS2SendChar(0xFA); PS2RecChar=0xCC; } else if(PS2RecChar==0xAA)//12 { OnPS2SendChar(0xAA); PS2RecChar=0xCC; } else if(PS2RecChar==0xFF)//13 { OnPS2SendChar(0xFA); Delay30us(); OnPS2SendChar(0xAA); Delay30us(); PS2RecChar=0xCC; } else ; }}//---------------------------------------------------------------------------void PS2Init(void){ IT0=0; //低电平触发中断 PX0=1; EX0=1; }//---------------------------------------------------------------------------extern void ProcessPS2(void);extern void PS2Init(void);void main(void){ unsigned char tem; PS2Init(); ProcessPS2(); while(1) { tem=Key_Scan(); switch(tem&0xff) { case 23 : break; default: { OnPS2SendChar(PS2Value[tem]); } break; } //开机应答,使电脑能识别到键盘 //other code }}