改写的 PS/2 键盘解码程序

2020-01-27 11:32发布

前段时间改写的PS2键盘解码程序
实测可以使用
但一直搞不懂如何写入键盘。
就是不知道如何通过单片机控制键盘的Caps Lock 、Num Lock 灯的亮灭,希望大虾指点指点。。。感谢!!



=====================================C文件========================================================
#include <reg52.h>  
#include "scancodes.h"
#include "ps2kbd.h"
#include "delay.h"       
//#include "LCD1602.h"  



/*-----------------------------------------------
  名称:PS2键盘驱动程序
  日期:2010.11
  修改:无
  内容:通过单片机读/写PS2键盘
  备注:本程序需使用外部中断口
------------------------------------------------*/


//---------IO引脚宏定义---------//
sbit Key_Data = P3^0 ;   //定义Keyboard引脚
sbit Key_CLK = P3^2;      //使用中断




//-----结构体------//
//--标识特殊按键---//
static struct key_sign
{         
char Shift:1;        //上档键
char CapsLock:1;          //大小写
char NumLock:1;          //小键盘锁
}Button;                          

//-----标志----//
bit BF;                                         //解码完毕标志
bit Key_UP;              //定义通码断码标志
bit E0Key=0;                         //E0开头的键盘码
bit Paritycheck=1;                 //奇偶校验标志


unsigned char KeyV;                 //键值
unsigned char IntNum;         //中断次数


/******************************************************************/
/*                    函数声明                                    */
/******************************************************************/
void Decode(unsigned char ScanCode);  //解码子程序
void keyVcache(unsigned char keyV);          //键值入口,keyV就是解码后返回的键码
void Keyboard_WRITE(unsigned char sentchar);  //写一字节到PS2键盘  






/*-----------------------------------------------
  名称:主机读取PS2键盘一字节
  日期:2010.11
  修改:无
  内容:读取PS2键盘返回值(未解码),外部中断法
  备注:键值存KeyV
------------------------------------------------*/
void Keyboard_READ(void) interrupt 0
{
if((IntNum > 0) && (IntNum < 9))
   {
        KeyV >>= 1;                //因键盘数据是低>>高,结合上一句所以右移一位
        if (Key_Data)
        {
     KeyV |= 0x80;             //当键盘数据线为1时到最高位
         Paritycheck=~Paritycheck; //奇偶校验位,数据奇数1为0
        };
   };           
if(IntNum==9)
  {
   if(Key_Data!=Paritycheck)
     {
      KeyV=0x00;                            //奇偶校验错误,清空数据
     };
  };
  IntNum++;
while (!Key_CLK);                             //等待PS/2CLK拉高
if(IntNum > 10)
  {
   IntNum = 0;                  //当中断11次后表示一帧数据收完,清变量准备下一次接收
   BF = 1;                      //标识有字符输入完了
   EA = 0;                      //关中断等显示完后再开中断
   Paritycheck=1;                                 //一次接收接收,初始化奇偶校验位
  };        
}



/*-----------------------------------------------
  名称:PS2键盘解码
  日期:2010.11
  修改:无
  内容:解码键盘返回值
  传入:ScanCode 键盘返回值
  传出:无
  相关寄存器:BF,Shift,CapsLock,NumLock,Key_UP,E0_Key
------------------------------------------------*/
void Decode(unsigned char ScanCode) // 注意:如SHIFT+G为12H 34H F0H 34H F0H 12H,也就是说shift的通码+G的通码+shift的断码+G的断码
{
unsigned char TempCyc;

if (!Key_UP)                        // 当键盘按下时
        {
        switch (ScanCode)
                        {
                        case 0xF0 :             // 当收到0xF0,Key_UP置1表示断码开始
                                Key_UP = 1;
                                break;

                        case 0x12 :             // 左 SHIFT
                                Button.Shift = 1;
                                break;
                        case 0x58 :                                // CapsLock键
                            Button.CapsLock = ~Button.CapsLock;
                                break;
                        case 0x59 :             // 右 SHIFT
                                Button.Shift = 1;
                                break;

                        case 0x77 :                                // 小键盘锁
                            Button.NumLock = ~Button.NumLock;
                                break;

                        case 0xe0 :                                // 以E0开头的键码
                            E0Key = 1;
                                break;

                        case 0xFA :                            // 键盘应答信号
                            break;

                        default:
                           /*如果数据不是F0,E0或LOCK键,则进行:查表对比键盘码,输出键值*/
                            
                                if(Button.Shift)           // 如果SHIFT按下
                                        {
                                        for (TempCyc = 0;(kbdasciicode[TempCyc][0]!=ScanCode)&&(TempCyc<49); TempCyc++); //查表显示
                                        if (kbdasciicode[TempCyc][0] == ScanCode)
                                                {                                         
                                                keyVcache(kbdasciicode[TempCyc][2]);  //返回大写字母或第二功能键值
                                                break;
                                            };                                                 
                     }
                                else                // 没有按下SHIFT
                    {
                                        for(TempCyc = 0; (kbdasciicode[TempCyc][0]!=ScanCode)&&(TempCyc<49); TempCyc++); //查表显示
                                        if (kbdasciicode[TempCyc][0] == ScanCode)
                       {
                                            if(Button.CapsLock&(TempCyc<27))        // 如果CapsLock有效且按下字母键
                                                {
                                                  keyVcache(kbdasciicode[TempCyc][2]); // 返回大写字母键值
                                                }
                                                else
                                                {
                                                keyVcache(kbdasciicode[TempCyc][1]); // 否则返回小写或第一功能键值
                                                };
                                                break;
                                             };
                    };
                                //带E0开头类按键 查表
                                if(E0Key)          //如果属于E0开头的键盘码
                                        {
                                        E0Key=0;
                                        for (TempCyc = 0;(E0startedcode[TempCyc][0]!=ScanCode)&&(TempCyc<18); TempCyc++); //查表显示
                                        if (E0startedcode[TempCyc][0] == ScanCode)
                                                {
                                                   keyVcache(E0startedcode[TempCyc][1]);
                                                break;
                                            };
                                          
                     };
                                //控制类键以及小键盘按键 查表
                           for(TempCyc = 0; (kbdcontrolcode[TempCyc][0]!=ScanCode)&&(TempCyc<37); TempCyc++); //查表显示
                                  {
                                        if (kbdcontrolcode[TempCyc][0] == ScanCode)
                       {
                                            if(Button.NumLock&(TempCyc<14))
                                                {
                                                //NumLock上锁,小键盘不返回键码
                                                }
                                                else
                                                {
                                              keyVcache(kbdcontrolcode[TempCyc][1]);
                                                };
                                             };
                                  };                               
                        };
        }
else
        {
        Key_UP = 0;
        switch (ScanCode) //当键松开时不处理判码,如G 34H F0H 34H 那么第二个34H不会被处理
                        {
                        case 0x12 : // 左 SHIFT
                                Button.Shift = 0;
                                break;

                        case 0x59 : // 右 SHIFT
                                Button.Shift = 0;
                            break;
                        };
        };
BF = 0; //标识字符处理完了
}




/*-----------------------------------------------
  名称:主机写PS2键盘
  日期:2010.11
  修改:无
  内容:写一个字节入PS2键盘
  传入:sentchar 传入键盘的数据
------------------------------------------------*/
void Keyboard_WRITE(unsigned char sentchar)          //ps2主设备向从设备发送数据
{
unsigned char sentbit_cnt = 0x00;
unsigned char sentchar_chk = 0x00;
EX0=0; //关外部中断0

//发起一个传送,发起始位
Key_CLK = 0; //将时钟线拉低并保持100 us
delay_nus(100);
Key_Data= 0; //起始位
Key_CLK = 1;

//发送DATA0-7
for(sentbit_cnt=0;sentbit_cnt< 8;sentbit_cnt++)
{
while(Key_CLK)
_nop_(); //等待时钟线变为低
Key_Data = sentchar&0x01;//发送数据
if(Key_Data) sentchar_chk++; //计算校验
while(!Key_CLK) _nop_(); //等待时钟线变高
sentchar>>=1; //待发送数据右移一位
};

//发送校验位
while(Key_CLK) _nop_(); //等待时钟线变低
switch(sentchar_chk)
{
case 0:
case 2:
case 4:
case 6:Key_Data = 1;break;//奇校验
case 1:
case 3:
case 5:
case 7:Key_Data = 0;break;//奇校验
default:break;
};

while(!Key_CLK) _nop_(); //等待时钟线变高
while(Key_CLK) _nop_(); //等待时钟线变低
Key_Data =1;//发送停止位,停止位总为1
while(!Key_CLK) _nop_(); //等待时钟线变高
while(Key_CLK) _nop_(); //等待时钟线变低
//接收ACK
//if(PS2_SGN_DATA) error();
//ACK信号由键盘发出,总为低电平
while(!Key_CLK) _nop_(); //等待时钟线变高
EX0= 1; //开外部中断0
}



/*-----------------------------------------------
  名称:键值传入
  日期:2010.11
  修改:无
  内容:键值就传入到此函数,可通过对该函数编写按键处理
  传入:解码后的按键键值
------------------------------------------------*/
void keyVcache(unsigned char keyV)
{
unsigned char i;

ShowChar(i++,keyV);
   if(i>32)
   {
   i=0;
   WriteCommand(0x01);
   };
}


//参考:http://www.picavr.com/news/2010-08/2296.htm


=====================================资料========================================================
程序ourdev_608918WOZS4Q.rar(文件大小:41K) (原文件名:ps2接口测试.rar)
PS2技术参考 本论坛已有ourdev_608919ZYXUGS.pdf(文件大小:667K) (原文件名:ps2技术参考.pdf)
不错的教程 网上收集ourdev_608920FR5THD.mht(文件大小:421K) (原文件名:转贴:PS2键盘的单片机编程 (重要!).mht)

=====================================测试图片=====================================================

以下1602显示的文字都是由PS2键盘输入的。

测试图片1 (原文件名:20110103431.jpg)


不知道键盘的Caps Lock灯怎么控制亮灭呢? (原文件名:20110103432.jpg)


不知道键盘的Caps Lock灯怎么控制亮灭呢? (原文件名:20110103434.jpg)


不知道PS2键盘怎么初始化呢? (原文件名:20110103433.jpg)


PS2硬件接口 (原文件名:连接图.jpg)
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
34条回答
tomatowo
2020-01-29 17:21
PC机发送的命令字        16进制值        键盘发送的命令字        16进制值

置位/复位命令        ED        自检成功码        AA
允许              F4        自检错误码        FC
ECHO                 EE        ECHO                 EE
复位              FF        确认                 FA
重新发送                 FE        重新发送                 FE

一周热门 更多>