⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2.c

📁 基于8051单片机的PS2键盘的C语言代码。
💻 C
字号:
/*****************************************************************************/
//main.c
//功能:从PS/2口接受键盘信息,解码成ACSII码,通过UART发送出去,并且控制键盘
//修改:
//时间:2006-7-8
//作者:R.S.J
/*****************************************************************************/

#include <reg51.h>
#include <intrins.h>
#include "PS2.h"

#define EINT (EA = 1)
#define DINT (EA = 0)

#define MAXBUFFER 15

#define WAITFORKEYBOARDPULSE while(!scl); while(scl)

#define COMMAND_RESET 0xFF //命令:复位键盘
#define COMMAND_READID 0xF2 //命令:读键盘ID
#define COMMAND_SETSTATUS 0xED //命令:设置状态CapsLock,NumLock,ScrollLock
#define COMMAND_SETRATE 0xF3 //命令:设置速率,延时
#define COMMAND_ENABLE 0xF4 //命令:使能键盘
#define CAPSLOCK_EN 0x04 //使能CapsLock 灯
#define NUMLOCK_EN 0x02 //使能NumLock 灯
#define SCROLLLOCK_EN 0x01 //使能ScrollLock灯
#define CAPSLOCK_DIS 0x03 //关闭CapsLock灯
#define NUMLOCK_DIS 0x05 //关闭NumLock灯
#define SCROLLLOCK_DIS 0x06 //关闭ScrollLock灯
#define DISALL 0x00 //关闭所有灯


#define CODE_POST 0xAA //键盘上电自检成功 Power On Self Test
#define CODE_ACK 0xFA //键盘应答码
#define CODE_ECHO 0xEE //键盘的回应码
#define CODE_BREAK 0xF0 //断码
#define CODE_EXTEND 0xE0 //扩展码
#define CODE_PAUSE 0xE1 //Pause键起始码 E1+14+77/E1+F0+14/F0+77
#define CODE_LSHIFT 0x12 //左Shift键通码
#define CODE_RSHIFT 0x59 //右Shift键通码
#define CODE_LCTRL 0x14 //左CTRL键通码
#define CODE_RCTRL 0x14 //右CTRL键通码 0xE0,0x14
#define CODE_LALT 0x11 //左ALT键通码
#define CODE_RALT 0x11 //右ALT键通码 0xE0,0x11
#define CODE_NUMLOCK 0x77 //NumLock键
#define CODE_CAPSLOCK 0x58 //CapsLock键
#define CODE_SCROLLLOCK 0x7E//SCROLLLOCK键

/* 函数定义 */
unsigned char ReadPS2(); //读PS2端口获取PS2发送的数据
void KeyScan(); //获得键值
void KeyTransmit(); //发送键值
void Order(unsigned char); //向键盘发送命令
void KickDog(); //喂狗
void Delay(unsigned char);
void LedLock(unsigned char);
/* 变量定义 */
sbit sda = P3^7; //P3.7做为数据线
sbit scl = P3^2; //P3.2做为时钟线
sbit key_sw = P1^1; //P1.2作为键盘电源开关

int i;
unsigned char KeyCodeBuff[MAXBUFFER+1] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//键值缓存
unsigned char KeyCodeSum = 0; //键码数
bit KeyFlag = 0; //有键标志
bit KeyUpFlag = 0; //键弹起标志
bit KeyExtendFlag = 0; //扩展键标志
bit KeyLedLockFlag = 0; //三个Led键被按下的标志
bit KeyBoardConnectFlag = 0; //键盘连接标志
bit KeyPauseFlag = 0; //Pause键标志
bit KeyMakeCodeFlag = 0; //键盘发送通码标志
/*
bit CapsLockFlag = 0; //CapsLock标志
bit NumLockFlag = 0; //NumLock标志
bit ScrollLockFlag = 0; //ScrollLock标志
*/
unsigned char KeyIDLo = 0; //键盘ID低字节
unsigned char KeyIDHi = 0; //键盘ID高字节
unsigned char LedStatus = 0; //NumLock,CapsLock,ScrollLock灯控制
/*********************************************************/
//函数:main()
//功能:主函数
//输入:无
//输出:无
//描述:
/*********************************************************/
void main()
{
DINT; //关中断

for(i=0;i<1000;i++)
;//延时稳定

/* 初始化变量 */
sda = 0;
scl = 0; //端口设置为高
key_sw = 1; //关键盘
for(i=0;i<1000;i++)
Delay(10);
for(i = 0;i<16;i++)
{
KeyCodeBuff = 0;
}
KeyCodeSum = 0;
KeyFlag = 0;
KeyUpFlag = 0;
KeyExtendFlag = 0;
KeyLedLockFlag = 0;
KeyBoardConnectFlag = 0;
KeyPauseFlag = 0;
KeyMakeCodeFlag = 0;
KeyIDLo = 0;
KeyIDHi = 0;
LedStatus = 0;

TMOD = 0x22; //T1为波特率发生器设置19200波特率
//T0为采样键盘时钟发生器
TL1 = 0xFD;
TH1 = 0xFD;
// TL0 =
// TH0 =
PCON |= 0x80; //SMOD设置为1
SCON = 0x50; //串口控制寄存器
//工作方式
//非多机通讯方式
//允许接收
//

TR1 = 1; //定时器1开始

IT0 = 0; //低电平引起中断

ES = 1; //开串口中断
EX0 = 1; //开外部0中断
key_sw = 0; //开键盘电源
scl = 1;
sda = 1;

Delay(1);
while(!KeyBoardConnectFlag)
ReadPS2();//等待键盘自检成功

Order(COMMAND_RESET); //复位键盘
ReadPS2(); //等待键盘应答
Delay(5);

Order(COMMAND_SETSTATUS);//设置状态灯CapsLock,NumLock,ScrollLock
ReadPS2(); //等待键盘应答
LedStatus = DISALL;
Order(LedStatus); //关闭所有灯
ReadPS2(); //等待键盘应答
/*
Order(COMMAND_READID); //读键盘ID
ReadPS2(); //等待键盘应答
KeyIDLo = ReadPS2(); //获得键盘ID低字节
KeyIDHi = ReadPS2(); //获得键盘ID高字节
*/
LedStatus = NUMLOCK_EN; //开NumLock灯
Order(COMMAND_SETSTATUS); 
ReadPS2(); //等待应答
Order(LedStatus); //
ReadPS2(); //等待应答
Order(COMMAND_SETRATE); //设置速率延时
ReadPS2(); //等待应答
Order(0x20); //500ms/30
ReadPS2();
Order(COMMAND_ENABLE); //使能键盘
ReadPS2();
Order(COMMAND_SETRATE); //设置速率延时
ReadPS2();
Order(0x20); //
ReadPS2();

Delay(200); //延时

EINT; //开总中断

for(;;)
{
//KeyScan();//扫描键盘
if(KeyFlag == 1)
{
KeyFlag = 0;
KeyTransmit();//
}

KickDog();
}
}

/*********************************************************/
//函数:uart
//功能:串口中断
//输入:无
//输出:无
//描述:
/*********************************************************/
void uart() interrupt 4 using 2
{
if(RI == 1) //接收中断
{
RI= 0;

}
else if(TI == 1) //发送中断
{
if(KeyCodeSum >1)
{
SBUF = KeyCodeBuff[--KeyCodeSum]; 
}
else
{
KeyCodeSum = 0; 
}
TI = 0;
}
}
/*********************************************************/
//函数:KeyTransmit()
//功能:定时器0中断
//输入:
//输出:
//描述:
/*********************************************************/
void KeyTransmit()
{
while(TI == 1);
SBUF = KeyCodeBuff[--KeyCodeSum]; //发送键值
//KeyCodeSum = 0; //
}
/*********************************************************/
//函数:timer0()
//功能:定时器0中断
//输入:
//输出:
//描述:
/*********************************************************/
void timer0() interrupt 1 using 3
{

}
/*********************************************************/
//函数:ex0()
//功能:外部中断0服务程序
//输入:
//输出:
//描述:
/*********************************************************/
void ex0() interrupt 0 using 3
{ //时钟线变低
unsigned char bitCount;
unsigned char KeyCode = 0;
if(KeyCodeSum < MAXBUFFER) KeyCodeBuff[KeyCodeSum] = 0;
for(bitCount = 8; bitCount != 0; bitCount --) // 把起始位算入
{
WAITFORKEYBOARDPULSE; // 等待一个有效的下跳沿
KeyCode >>= 1; // 按照PS2格式,数据低位在前
scl = 1;
sda = 1;
if(sda == 1)
{
KeyCode |= 0x80; // 得到有效的数据位
}
}
WAITFORKEYBOARDPULSE; // 等待按键发送效验位
WAITFORKEYBOARDPULSE; // 等待按键发送终止位
while(!scl); // 等待键盘把时钟线拉高
switch(KeyCode)
{
case CODE_POST:
KeyBoardConnectFlag = 1;
break;
case CODE_ACK: //键盘应答
Order(LedStatus);
break;
case CODE_ECHO: //键盘的echo回应码 
break;
case 0xFE:
break; 
case CODE_BREAK: //键盘发送的是断码
KeyUpFlag = 1;
break;
case CODE_EXTEND: //键盘发送的是扩展码
if(KeyExtendFlag == 0)
{
KeyExtendFlag = 1;
KeyCodeBuff[KeyCodeSum] = KeyCode;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
} 
break;
case CODE_PAUSE: //键盘发送的是Pause键的键码
KeyPauseFlag = 1;
KeyCodeBuff[KeyCodeSum] = KeyCode;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
break; 
case CODE_NUMLOCK:
if(KeyPauseFlag == 1 || (KeyMakeCodeFlag == 0 && KeyUpFlag))
{
KeyFlag = 1; //如果是Pause键的键码(E1+14+77)则77代表键码结束直接发送
if(KeyMakeCodeFlag == 0) //Pause键发送的键码是(F0+77)
{
KeyCodeBuff[KeyCodeSum] = CODE_PAUSE;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
KeyCodeBuff[KeyCodeSum] = 0x14;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
}
KeyUpFlag = 0;
KeyMakeCodeFlag = 0;
KeyPauseFlag = 0;
break;
} 

case CODE_CAPSLOCK:

case CODE_SCROLLLOCK: //发送的是三个LED控制键通码
KeyLedLockFlag = 1;

default: //键盘发送的是通码
if(KeyUpFlag == 1)
{ //发送的是断码之后的通码
KeyFlag = 1; //有正常键被按下
KeyUpFlag = 0; //键弹起标志
KeyExtendFlag = 0; //扩展键标志
KeyMakeCodeFlag = 0; //键通码标志
if(KeyPauseFlag == 1) //Pause键被按下发送的键码是(E1+F0+14) 
{
KeyPauseFlag = 0;
KeyCodeBuff[KeyCodeSum] = KeyCode;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
break;
}
if(KeyLedLockFlag == 1)
{
KeyLedLockFlag = 0;
switch(KeyCode)
{
case CODE_CAPSLOCK:
if(LedStatus & CAPSLOCK_EN)
{
LedStatus &= CAPSLOCK_DIS;
}
else
{
LedStatus |= CAPSLOCK_EN;
} 
break;
case CODE_NUMLOCK:
if(LedStatus & NUMLOCK_EN)
{
LedStatus &= NUMLOCK_DIS;
}
else
{
LedStatus |= NUMLOCK_EN;
}
break;
case CODE_SCROLLLOCK:
if(LedStatus & SCROLLLOCK_EN)
{
LedStatus &= SCROLLLOCK_DIS;
}
else
{
LedStatus |= SCROLLLOCK_EN;
} 
break;
}
Order(0xED); //设置Led

//Order(LedStatus);
//LedLock(LedStatus);
} 
}
else //通码
{
KeyCodeBuff[KeyCodeSum] = KeyCode;
if(KeyCodeSum < MAXBUFFER) KeyCodeSum++;
KeyMakeCodeFlag = 1;
} 
}
}
/*********************************************************/
//函数:KeyScan()
//功能:扫描键盘
//输入:
//输出:键值
//描述:
/*********************************************************/
/*
void KeyScan()
{
unsigned char KeyCode;
KeyCode = ReadPS2();
if(KeyCode == CODE_BREAK)
{

KeyFlag = 1;
}
else
{
KeyCodeBuff[KeyCodeSum] = KeyCode;
KeyCodeSum++;
}
}
*/
/*********************************************************/
//函数:ReadPS2()
//功能:扫描键盘
//输入:
//输出:键值
//描述:
/*********************************************************/\

unsigned char ReadPS2()
{
unsigned char KeyCode; //键盘键值
unsigned char bitCount; //位数
while(scl); // 等待键盘把时钟第一次拉低

for(bitCount = 8; bitCount != 0; bitCount --) // 把起始位算入
{
WAITFORKEYBOARDPULSE; // 等待一个有效的下跳沿
KeyCode >>= 1; // 按照PS2格式,数据低位在前
scl = 1;
sda = 1;
if(sda == 1)
{
KeyCode |= 0x80; // 得到有效的数据位
}
}
WAITFORKEYBOARDPULSE; // 等待按键发送效验位
WAITFORKEYBOARDPULSE; // 等待按键发送终止位
while(!scl); // 等待键盘把时钟线拉高
if(KeyCode == CODE_POST)
KeyBoardConnectFlag = 1;
return(KeyCode); // 返回按键扫描
}

/*********************************************************/
//函数:Order()
//功能:向键盘发送命令
//输入:命令
//输出:?
//描述:
/*********************************************************/
void Order(unsigned char orderByte)
{
unsigned char cnt;
unsigned char check;

//DINT; //关闭总中断,发送命令到键盘

scl = 0;
sda = 1;
for(cnt = 0xff; cnt != 0; cnt --); // 拉低时钟与数据并延时

sda = 0;
scl = 1;
for(cnt = 8; cnt != 0; cnt --)
{ // 发送八位数据,循环八次

while(scl);
if(orderByte & 0x01)
{
sda = 1; // 根据低位设定输出数据
check ++; // 如果输出一个1,效验记录数据加一
}
else
{
sda = 0;
}
orderByte >>= 1; // 命令字调整
while(!scl); // 输出脉冲
}
while(scl);
if(check % 2)
{ // 如果输出过偶数个脉冲
sda = 0; // 效验数据位置1
}
else
{
sda = 1; // 否则数据位置0
}
while(!scl);
while(scl);
sda = 1;
while(!scl); // 发送终止位
sda = 1;
scl = 1;
while((scl) | (sda)); // 等待ACK握手信号
while(!scl); //等待scl变高
//EINT; //开总中断
}
/*********************************************************/
//函数:void LedLock()
//功能:三个键盘的控制
//输入:三个键盘灯的控制
//输出:三个灯的状态
//描述:
/*********************************************************/
void LedLock(unsigned char LedLock)
{
Order(0xED); //控制命令字
Order(LedLock);
}
/*********************************************************/
//函数:KickDog()
//功能:喂狗
//输入:
//输出:?
//描述:
/*********************************************************/
void KickDog()
{


}
/*********************************************************/
//函数elay()
//功能:延时
//输入:延时时间设定值
//输出:?
//描述:
/*********************************************************/
void Delay(unsigned char Times)
{
unsigned char n;
n = 120;
for(;Times>0;Times--)
{
for(;n>0;n--)
;
}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -