找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 9305|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

51單片機(jī)模擬PS2協(xié)議制作5X5矩陣工業(yè)鍵盤

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:76127 發(fā)表于 2015-4-18 00:40 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
根據(jù)客戶的要求利用單片機(jī)制作一個(gè)小的工控鍵盤,將下面對(duì)應(yīng)的鍵值發(fā)送到電腦顯示,利用的協(xié)議就是PS2,單片機(jī)型號(hào)為stc89c52rc,晶振為12M;

 
 
 
1
0
6
5
4
3
2
7
8
9
減號(hào)
等號(hào)
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;   //設(shè)定標(biāo)志位
Key_line=0xe0;        //將P0口低5位全部設(shè)置位0
temp3=Key_list;     //讀取P2口的狀態(tài),若果P2口的值temp3:(temp3&0xff)!=0xff成立,表示有鍵按下
if(((temp3&0xff)!=0xff))  //有鍵按下條件判斷
{
    flag=1;
    //Key_line=0XFF;     //清零鍵盤行端口
    Key_list=0xff;        //清零鍵盤列端口
}
else
    flag=0;          //無(wú)鍵按下標(biāo)志
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用來(lái)保存行鍵盤數(shù)據(jù),temp3保存列鍵盤數(shù)據(jù)
unsigned char temp=0,flag=0;     //函數(shù)返回值temp
unsigned char i=0,key=0;   //i位循環(huán)控制變量,給行送數(shù)據(jù),key保存檢測(cè)鍵盤按下的標(biāo)志位
if((key=Key_Press())!=0)   //判斷是否有鍵按下
{
  delay(30);
  if((key=Key_Press())!=0)
  {
    for(i=0x01;i!=0x20;i=i<<1)  //循環(huán)控制變量,掃描5行
    {
     Key_line=(~i);        //將循環(huán)控制變量賦值行地址
     temp2 =(~i);     //保存行地址
     //temp2=Key_line;
     temp3=Key_list;      //讀取列地址數(shù)據(jù)
     switch((temp3&0xff)) //判斷是那列有鍵按下
     {
      case 0xfe:   //第一列有鍵按下
       switch((temp2&0xff)) //判斷第一列有鍵按下時(shí),對(duì)應(yīng)的行按鍵   
       {
        case 0xfe:
          temp=23;   //第一行有鍵按下
          break;  //該鍵無(wú)鍵盤號(hào)定義
        case 0xfd:    //第二行有鍵按下
          temp=PS2_6;flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字6,對(duì)應(yīng)的鍵盤掃描碼為0x36
          break;
        case 0xfb:    //第三行有鍵按下
          temp=PS2_7; flag=1;//對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字7,對(duì)應(yīng)的鍵盤掃描碼為0x3d
          break;
        case 0xf7:    //第四行有鍵按下
          temp=PS2_y; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母y,對(duì)應(yīng)的鍵盤掃描碼為0x35
          break;
        case 0xef:    //第五行有鍵按下
          temp=PS2_q ;flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的字母q,對(duì)應(yīng)的鍵盤掃描碼為0x15
          break;
       }
       break;
      
      case 0xfd:  
       switch((temp2&0xff))     // 第二列有鍵按下
       {
        case 0xfe:     //第一行有鍵按下
          temp=23;  //該鍵無(wú)鍵盤號(hào)定義
                 break;
        case 0xfd:     //第二行有鍵按下
          temp=PS2_5;flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字5,對(duì)應(yīng)的鍵盤掃描碼為0x2e
          break;
        case 0xfb:      //第三行有鍵按下
          temp=PS2_8; flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字8,對(duì)應(yīng)的鍵盤掃描碼為0x8e
          break;
        case 0xf7:      //第四行有鍵按下
          temp=PS2_u;flag=1;   //對(duì)應(yīng)鍵值位PS2鍵盤的字母u,對(duì)應(yīng)的鍵盤掃描碼為0x3c
          break;
        case 0xef:       //第五行有鍵按下
          temp=PS2_w ; flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的字母w,對(duì)應(yīng)的鍵盤掃描碼為0x1d
          break;
       }
       break;
      
      case 0xfb:
       switch((temp2&0xff))    // 第三列有鍵按下
       {
        case 0xfe:     //第一行有鍵按下
          temp=23;  //該鍵無(wú)鍵盤號(hào)定義
                 break;
        case 0xfd:     //第二行有鍵按下
          temp=PS2_4; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字4,對(duì)應(yīng)的鍵盤掃描碼為0x25
          break;
        case 0xfb:     //第三行有鍵按下
          temp=PS2_9; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字9,對(duì)應(yīng)的鍵盤掃描碼為0x46
          break;
        case 0xf7:     //第四行有鍵按下
          temp=PS2_i; flag=1; //對(duì)應(yīng)鍵值位PS2鍵盤的字母i,對(duì)應(yīng)的鍵盤掃描碼為0x43
          break;
        case 0xef:      //第五行有鍵按下
          temp=PS2_e; flag=1;   //對(duì)應(yīng)鍵值位PS2鍵盤的字母e,對(duì)應(yīng)的鍵盤掃描碼為0x24
          break;
       }
       break;
  
      case 0xf7:
       switch((temp2&0xff))      // 第四列有鍵按下
       {
        case 0xfe:      //第一行有鍵按下
          temp=PS2_1; flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字1,對(duì)應(yīng)的鍵盤掃描碼為0x16
                 break;
        case 0xfd:      //第二行有鍵按下
          temp=PS2_3; flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字3,對(duì)應(yīng)的鍵盤掃描碼為0x26
          break;
        case 0xfb:      //第三行有鍵按下
          temp=PS2_dec;flag=1;  //對(duì)應(yīng)鍵值位PS2鍵盤的減號(hào),對(duì)應(yīng)的鍵盤掃描碼為0x4e
          break;
        case 0xf7:       //第四行有鍵按下
          temp=PS2_o; flag=1;   //對(duì)應(yīng)鍵值位PS2鍵盤的字母o,對(duì)應(yīng)的鍵盤掃描碼為0x44
          break;
        case 0xef:      //第五行有鍵按下
          temp=PS2_r; flag=1;    //對(duì)應(yīng)鍵值位PS2鍵盤的字母r,對(duì)應(yīng)的鍵盤掃描碼為0x2d
          break;
       }        
       break;
  
      case 0xef:
       switch((temp2&0xff))      // 第五列有鍵按下
       {
        case 0xfe:         //第一行有鍵按下
          temp=PS2_0; flag=1;   //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字0,對(duì)應(yīng)的鍵盤掃描碼為0x45
                 break;
        case 0xfd:         //第二行有鍵按下
          temp=PS2_2; flag=1;     //對(duì)應(yīng)鍵值位PS2鍵盤的數(shù)字2,對(duì)應(yīng)的鍵盤掃描碼為0x1e
          break;
        case 0xfb:       //第三行有鍵按下
          temp=PS2_eq;flag=1;     //對(duì)應(yīng)鍵值位PS2鍵盤的等號(hào),對(duì)應(yīng)的鍵盤掃描碼為0x55
          break;
        case 0xf7:       //第四行有鍵按下
          temp=PS2_p;flag=1;     //對(duì)應(yīng)鍵值位PS2鍵盤的字母p,對(duì)應(yīng)的鍵盤掃描碼為0x4d
          break;
        case 0xef:        //第五行有鍵按下
          temp=PS2_t;flag=1;    //對(duì)應(yīng)鍵值位PS2鍵盤的字母t,對(duì)應(yīng)的鍵盤掃描碼為0x2c
          break;
       }
       break;  
     }
    //P0=0XFF;          //每當(dāng)檢測(cè)完一行時(shí)清零行端口和列端口
    //P2=0xff;
    if((key=Key_Press())!=0);
    delay(30);
    }
  }   
}
else  temp=23;     //無(wú)鍵按下返回?cái)?shù)字23,對(duì)應(yīng)數(shù)組內(nèi)的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);//奇校驗(yàn)位
if(P==ParityBit);
PS2RecChar=ReceChar;
}
//---------------------------------------------------------------------------
void OnPS2SendChar(BYTE dat)
{
BOOL ParityBit;
BYTE i;
ACC=dat;
CY=P;
ParityBit=(BOOL)(CY?0x00:0x80);//奇校驗(yàn)位

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--)//延時(shí)等待大鍵盤的動(dòng)作
{
  for(i=0;i<0x88;i++)//檢查是否有數(shù)據(jù)處理 0x88
  {
   if(H_CLK==0)//有動(dòng)作則是大鍵盤存在
   {
    OnKeyBoardOnline(TRUE);//大鍵盤存在,開(kāi)機(jī)由大鍵盤應(yīng)答
    IE0=0;
    EX0=1;
    return ;//存在的話置標(biāo)志位,并返回
   }
  }
}
OnKeyBoardOnline(FALSE);//大鍵盤不存在,由小鍵盤應(yīng)答

//轉(zhuǎn)到接收
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; }//如果時(shí)鐘被拉低,則有錯(cuò)誤發(fā)生
}
         
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; //低電平觸發(fā)中斷
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;   
  }
  //開(kāi)機(jī)應(yīng)答,使電腦能識(shí)別到鍵盤
  //other code
}
}
仿真矩陣鍵盤電路圖,該電路未連接PS2,但可通過(guò)LED燈觀察每個(gè)按鍵按下之后的鍵值返回知否和第二套鍵盤碼對(duì)應(yīng)一致



第二套鍵值碼對(duì)應(yīng)表:





分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:135507 發(fā)表于 2016-7-30 09:02 | 只看該作者
這個(gè) PS2.h的頭文件去哪里找呀
回復(fù)

使用道具 舉報(bào)

板凳
ID:135566 發(fā)表于 2016-7-30 23:54 | 只看該作者
不錯(cuò),挺好
回復(fù)

使用道具 舉報(bào)

地板
ID:258695 發(fā)表于 2018-3-13 16:43 | 只看該作者
"這個(gè) PS2.h的頭文件去哪里找呀"
同問(wèn)。。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表