找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8449|回复: 3
收起左侧

51单片机模拟PS2协议制作5X5矩阵工业键盘

[复制链接]
ID:76127 发表于 2015-4-18 00:40 | 显示全部楼层 |阅读模式
根据客户的要求利用单片机制作一个小的工控键盘,将下面对应的键值发送到电脑显示,利用的协议就是PS2,单片机型号为stc89c52rc,晶振为12M;

 
 
 
1
0
6
5
4
3
2
7
8
9
减号
等号
y
u
i
o

p
q
w
e
r
t


#include <reg51.h>
#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
}
}
仿真矩阵键盘电路图,该电路未连接PS2,但可通过LED灯观察每个按键按下之后的键值返回知否和第二套键盘码对应一致



第二套键值码对应表:





回复

使用道具 举报

ID:135507 发表于 2016-7-30 09:02 | 显示全部楼层
这个 PS2.h的头文件去哪里找呀
回复

使用道具 举报

ID:135566 发表于 2016-7-30 23:54 | 显示全部楼层
不错,挺好
回复

使用道具 举报

ID:258695 发表于 2018-3-13 16:43 | 显示全部楼层
"这个 PS2.h的头文件去哪里找呀"
同问。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表