?? ps2.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()
//功能:發送鍵值
//輸入:
//輸出:
//描述:
/*********************************************************/
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 + -