前段时间改写的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)
置位/复位命令 ED 自检成功码 AA
允许 F4 自检错误码 FC
ECHO EE ECHO EE
复位 FF 确认 FA
重新发送 FE 重新发送 FE
一周热门 更多>