close
http://www.computer-engineering.org/ps2keyboard/
http://www.computer-engineering.org/ps2protocol/
老外的基本資料
http://www.arduino.cc/playground/ComponentLib/Ps2mouse
現成的測試用具
http://blog.ednchina.com/wormchen/134613/message.aspx
參考祖國同胞的以上資料, 雖然不是100%合用, 但是比自己從零開始好.
作者的源碼是 G2313的簡體版, 所以要翻譯成 BIG5碼, 不然看到亂碼一堆. 翻譯的結果如下,
/************************************************************************
*Copyright (c) 2007 陳崇 *
*All rights reserved *
*文 件 名: main.c *
*說 明: PS/2鍵盤主程序 *
* 簡單的往串口發送PS/2鍵盤按下鍵的ASIIC *
*主要硬件: AtemlMega48(外部7.3728M) M48Dev試驗板 *
*編譯環境: WinAVR 20070525 *
*當前版本: 1.0 *
*作 者: 陳崇 *
*完成日期: 2008年7月15日16:17:38 *
*取代版本: 1.0 *
*原作 者: 陳崇 *
*完成日期: 2008年7月15日16:17:43 *
************************************************************************/
#include < avr/io.h >
#include < util/delay.h >
#include < avr/interrupt.h >
#include < avr/pgmspace.h >
#define BAUDRATE 9600
#define PS2_DB_INPUT (PINC & (1 << PC0))
#define NULL 0xFF
#define TRUE 1
#define FALSE 0
typedef struct _PS2_KEY_STATUS //定義新的按鍵狀態結構伐類型
{
unsigned char bKeyNewFlag; //新鍵標志位
unsigned char bBreakFlag; //斷碼標志位
unsigned char bShiftFlag; //shift鍵按下標志
unsigned char bKeyAsiic; //按鍵的的ASIIC碼值
}PS2_KEY_STATUS;
const unsigned char PS2CodeUnShift[][2] PROGMEM = //shift鍵沒按下譯碼表
{
{0x0e, '`'},
{0x15, 'q'},
{0x16, '1'},
{0x1a, 'z'},
{0x1b, 's'},
{0x1c, 'a'},
{0x1d, 'w'},
{0x1e, '2'},
{0x21, 'c'},
{0x22, 'x'},
{0x23, 'd'},
{0x24, 'e'},
{0x25, '4'},
{0x26, '3'},
{0x29, ' '},
{0x2a, 'v'},
{0x2b, 'f'},
{0x2c, 't'},
{0x2d, 'r'},
{0x2e, '5'},
{0x31, 'n'},
{0x32, 'b'},
{0x33, 'h'},
{0x34, 'g'},
{0x35, 'y'},
{0x36, '6'},
{0x39, ','},
{0x3a, 'm'},
{0x3b, 'j'},
{0x3c, 'u'},
{0x3d, '7'},
{0x3e, '8'},
{0x41, ','},
{0x42, 'k'},
{0x43, 'i'},
{0x44, 'o'},
{0x45, '0'},
{0x46, '9'},
{0x49, '.'},
{0x4a, '/'},
{0x4b, 'l'},
{0x4c, ';'},
{0x4d, 'p'},
{0x4e, '-'},
{0x52, '\''},
{0x54, '['},
{0x55, '='},
{0x5b, ']'},
{0x5d, '\\'},
{0x61, '<'},
{0x69, '1'},
{0x6b, '4'},
{0x6c, '7'},
{0x70, '0'},
{0x71, '.'},
{0x72, '2'},
{0x73, '5'},
{0x74, '6'},
{0x75, '8'},
{0x79, '+'},
{0x7a, '3'},
{0x7b, '-'},
{0x7c, '*'},
{0x7d, '9'},
{0x00, 0x00}
};
const unsigned char PS2CodeShift[][2] PROGMEM = //shift鍵按下譯碼表
{
0x0e,'~',
0x15,'Q',
0x16,'!',
0x1a,'Z',
0x1b,'S',
0x1c,'A',
0x1d,'W',
0x1e,'@',
0x21,'C',
0x22,'X',
0x23,'D',
0x24,'E',
0x25,'$',
0x26,'#',
0x29,' ',
0x2a,'V',
0x2b,'F',
0x2c,'T',
0x2d,'R',
0x2e,'%',
0x31,'N',
0x32,'B',
0x33,'H',
0x34,'G',
0x35,'Y',
0x36,'^',
0x39,'L',
0x3a,'M',
0x3b,'J',
0x3c,'U',
0x3d,'&',
0x3e,'*',
0x41,'<',
0x42,'K',
0x43,'I',
0x44,'O',
0x45,')',
0x46,'(',
0x49,'>',
0x4a,'?',
0x4b,'L',
0x4c,':',
0x4d,'P',
0x4e,'_',
0x52,'"',
0x54,'{',
0x55,'+',
0x5b,'}',
0x5d,'|',
0x61,'>',
0x69,'1',
0x6b,'4',
0x6c,'7',
0x70,'0',
0x71,'.',
0x72,'2',
0x73,'5',
0x74,'6',
0x75,'8',
0x79,'+',
0x7a,'3',
0x7b,'-',
0x7c,'*',
0x7d,'9',
0,0
};
PS2_KEY_STATUS PS2KeyStatus;
unsigned char g_KeyAsiic;
/************************************************************************
*名稱: void DelayMS(unsigned int uiMS)
*功能: 延時nms
*參數: 無
*返回: 無
************************************************************************/
void DelayMS(unsigned int wMS)
{
while(wMS--)
{
_delay_loop_2(2000); // 延時1ms(粗略)
}
}
/*************************************************************************
*名稱: void PORT_Init(void)
*功能: 端口初始化
*參數: 無
*返回: 無
*************************************************************************/
void PORT_Init(void)
{
PORTD |= (1 << PD1) | ( 1 << PD2) | ( 1 << PD3);
DDRD |= (1 << PD1); //PD1胔出胔出高電平,PD2胔入帶上拉
PORTC |= (1 << PC0); //PC0胔入帶上拉
}
void INT0_Init(void)
{
EICRA |= (1 << ISC01); //INT0下降沿觸發
EIMSK |= (1 << INT0); //使能INT0中斷
}
/************************************************************************
*名稱: void USART_Init(void)
*功能: 串口初始化
*參數: 無
*返回: 無
************************************************************************/
void USART_Init(void)
{
UCSR0C = (1 << UCSZ01)|(1 << UCSZ00);
//異步操作,8位數據,無奇偶校驗位,一個停止位
UBRR0L = (F_CPU / BAUDRATE / 16 - 1) % 256; //設瞞波特率
UBRR0H = (F_CPU / BAUDRATE / 16 - 1) / 256;
UCSR0B = (1 << RXCIE0)|(1 << RXEN0)|(1 << TXEN0);
//使能接收中斷,使能接收,使能發送
}
/************************************************************************
*名稱: void USART_PutChar(unsigned char bTxData)
*功能: 向串口發送一個字符
*參數: bTxData 要發送的字符
*返回: 無
************************************************************************/
void USART_PutChar(unsigned char bData)
{
while(!(UCSR0A&(1 << UDRE0))); //發送緩沖器是否准備就緒
UDR0 = bData; //將要發數據送數據緩沖器
}
/************************************************************************
*名稱: void USART_PutString(unsigned char *bString)
*功能: 向串口發送字反
*參數: *pbStringbString 要發送的字符串
*返回: 無
************************************************************************/
void USART_PutString(unsigned char *pbString)
{
while (*pbString)
{
USART_PutChar(*pbString++);
}
}
/************************************************************************
*名稱: unsigned char PS2_KeyDeCode(unsigned char bKeyCode)
*功能: PS2鍵盤解碼程序
*參數: bKeyCode 鍵盤碼
*返回: 按鍵的ASIIC碼
************************************************************************/
unsigned char PS2_KeyDeCode(unsigned char bKeyCode)
{
unsigned char i;
if (!PS2KeyStatus.bBreakFlag)//通碼
{
switch (bKeyCode)//開始翻譯掃描碼
{
case 0xF0: //鍵盤釋放隨後的一個字節是斷碼
{
PS2KeyStatus.bBreakFlag = 1;//斷碼標志瞞位
break;
}
case 0x12: //左shift鍵按下
{
PS2KeyStatus.bShiftFlag = 1; //shift標志瞞位
break;
}
case 0x59: //右shift鍵按下
{
PS2KeyStatus.bShiftFlag = 1; //shift標志瞞位
break;
}
default:
{
PS2KeyStatus.bBreakFlag = FALSE;
if(!PS2KeyStatus.bShiftFlag) //如果shift鍵沒有按下
{
for(i = 0; i < 65; i++)//查表找按鍵ASIIC碼
{
if(pgm_read_byte(PS2CodeUnShift[i]) == bKeyCode)
{
PS2KeyStatus.bKeyAsiic =
pgm_read_byte(PS2CodeUnShift[i] + 1);
PS2KeyStatus.bKeyNewFlag = TRUE;
break;
}
}
}
else //如果shift鍵按下
{
for(i=0; i < 65; i++)//查表找按鍵ASIIC碼
{
if(pgm_read_byte(PS2CodeShift[i]) == bKeyCode)
{
PS2KeyStatus.bKeyAsiic =
pgm_read_byte(PS2CodeShift[i] + 1);
PS2KeyStatus.bKeyNewFlag = TRUE;
break;
}
}
}
break;
}
}
}
else //斷碼
{
PS2KeyStatus.bBreakFlag = 0; //將斷碼標志復位
switch (bKeyCode) //檢測shift鍵釋放
{
case 0x12 : //左shift鍵
PS2KeyStatus.bShiftFlag = 0;
break;
case 0x59 : //右shift鍵
PS2KeyStatus.bShiftFlag = 0;
break;
default:
break;
}
}
}
/************************************************************************
*名稱: ISR(INT0_vect )
*功能: INT0中斷服務程序
*參數: 無
*返回: 無
*************************************************************************/
ISR(INT0_vect )
{
static char bOddParity = 0;
static unsigned char bBitCounter = 0; //鍵盤幀位計數
static unsigned char bKeyCode;
bBitCounter++;
if(bBitCounter == 1)//START位
{
if(PS2_DB_INPUT != 0)
{
bBitCounter = 0;
}
return;
}
else if(bBitCounter > 1 && bBitCounter < 10) //接收8位數據
{
bKeyCode >>= 1;
if(PS2_DB_INPUT)
{
bKeyCode |= 0x80;
bOddParity++;
}
return;
}
else if(bBitCounter == 10)
{
if(bKeyCode ^ (bOddParity & 0x01)) //奇校驗正確
{
PS2_KeyDeCode(bKeyCode); //解碼
}
else
{
bBitCounter = 0;
}
return;
}
else if(bBitCounter == 11) //11位數據接收完畢
{
bBitCounter = 0;
bOddParity = 0;
return;
}
}
/************************************************************************
*名稱: unsigned char PS2_KeyScan(void)
*功能: PS2鍵盤掃描程序
*參數: 無
*返回: 新按下按鍵的ASIIC碼
*************************************************************************/
unsigned char PS2_KeyScan(void)
{
unsigned char temp;
if(PS2KeyStatus.bKeyNewFlag == TRUE) //如果有新按鍵按下
{
PS2KeyStatus.bKeyNewFlag = FALSE; //復位新按鍵標志
if(PS2KeyStatus.bBreakFlag == FALSE) //如果不是斷碼
{
temp = PS2KeyStatus.bKeyAsiic;
PS2KeyStatus.bKeyAsiic = NULL;
return temp;
}
}
return NULL;
}
int main(void)
{
PORT_Init();
INT0_Init();
USART_Init();
PS2KeyStatus.bKeyNewFlag = FALSE; //初始化按鍵狀態結構伐變量
PS2KeyStatus.bBreakFlag = FALSE;
PS2KeyStatus.bShiftFlag = FALSE;
PS2KeyStatus.bKeyAsiic = NULL;
sei();
while(1)
{
g_KeyAsiic = PS2_KeyScan(); //獲取PS2按鍵ASIIC
if(g_KeyAsiic != NULL) //如果有按鍵按下
{
USART_PutChar(g_KeyAsiic); //像串口放松按鍵ASCCI
}
}
}
http://www.computer-engineering.org/ps2protocol/
老外的基本資料
http://www.arduino.cc/playground/ComponentLib/Ps2mouse
現成的測試用具
http://blog.ednchina.com/wormchen/134613/message.aspx
參考祖國同胞的以上資料, 雖然不是100%合用, 但是比自己從零開始好.
作者的源碼是 G2313的簡體版, 所以要翻譯成 BIG5碼, 不然看到亂碼一堆. 翻譯的結果如下,
/************************************************************************
*Copyright (c) 2007 陳崇 *
*All rights reserved *
*文 件 名: main.c *
*說 明: PS/2鍵盤主程序 *
* 簡單的往串口發送PS/2鍵盤按下鍵的ASIIC *
*主要硬件: AtemlMega48(外部7.3728M) M48Dev試驗板 *
*編譯環境: WinAVR 20070525 *
*當前版本: 1.0 *
*作 者: 陳崇 *
*完成日期: 2008年7月15日16:17:38 *
*取代版本: 1.0 *
*原作 者: 陳崇 *
*完成日期: 2008年7月15日16:17:43 *
************************************************************************/
#include < avr/io.h >
#include < util/delay.h >
#include < avr/interrupt.h >
#include < avr/pgmspace.h >
#define BAUDRATE 9600
#define PS2_DB_INPUT (PINC & (1 << PC0))
#define NULL 0xFF
#define TRUE 1
#define FALSE 0
typedef struct _PS2_KEY_STATUS //定義新的按鍵狀態結構伐類型
{
unsigned char bKeyNewFlag; //新鍵標志位
unsigned char bBreakFlag; //斷碼標志位
unsigned char bShiftFlag; //shift鍵按下標志
unsigned char bKeyAsiic; //按鍵的的ASIIC碼值
}PS2_KEY_STATUS;
const unsigned char PS2CodeUnShift[][2] PROGMEM = //shift鍵沒按下譯碼表
{
{0x0e, '`'},
{0x15, 'q'},
{0x16, '1'},
{0x1a, 'z'},
{0x1b, 's'},
{0x1c, 'a'},
{0x1d, 'w'},
{0x1e, '2'},
{0x21, 'c'},
{0x22, 'x'},
{0x23, 'd'},
{0x24, 'e'},
{0x25, '4'},
{0x26, '3'},
{0x29, ' '},
{0x2a, 'v'},
{0x2b, 'f'},
{0x2c, 't'},
{0x2d, 'r'},
{0x2e, '5'},
{0x31, 'n'},
{0x32, 'b'},
{0x33, 'h'},
{0x34, 'g'},
{0x35, 'y'},
{0x36, '6'},
{0x39, ','},
{0x3a, 'm'},
{0x3b, 'j'},
{0x3c, 'u'},
{0x3d, '7'},
{0x3e, '8'},
{0x41, ','},
{0x42, 'k'},
{0x43, 'i'},
{0x44, 'o'},
{0x45, '0'},
{0x46, '9'},
{0x49, '.'},
{0x4a, '/'},
{0x4b, 'l'},
{0x4c, ';'},
{0x4d, 'p'},
{0x4e, '-'},
{0x52, '\''},
{0x54, '['},
{0x55, '='},
{0x5b, ']'},
{0x5d, '\\'},
{0x61, '<'},
{0x69, '1'},
{0x6b, '4'},
{0x6c, '7'},
{0x70, '0'},
{0x71, '.'},
{0x72, '2'},
{0x73, '5'},
{0x74, '6'},
{0x75, '8'},
{0x79, '+'},
{0x7a, '3'},
{0x7b, '-'},
{0x7c, '*'},
{0x7d, '9'},
{0x00, 0x00}
};
const unsigned char PS2CodeShift[][2] PROGMEM = //shift鍵按下譯碼表
{
0x0e,'~',
0x15,'Q',
0x16,'!',
0x1a,'Z',
0x1b,'S',
0x1c,'A',
0x1d,'W',
0x1e,'@',
0x21,'C',
0x22,'X',
0x23,'D',
0x24,'E',
0x25,'$',
0x26,'#',
0x29,' ',
0x2a,'V',
0x2b,'F',
0x2c,'T',
0x2d,'R',
0x2e,'%',
0x31,'N',
0x32,'B',
0x33,'H',
0x34,'G',
0x35,'Y',
0x36,'^',
0x39,'L',
0x3a,'M',
0x3b,'J',
0x3c,'U',
0x3d,'&',
0x3e,'*',
0x41,'<',
0x42,'K',
0x43,'I',
0x44,'O',
0x45,')',
0x46,'(',
0x49,'>',
0x4a,'?',
0x4b,'L',
0x4c,':',
0x4d,'P',
0x4e,'_',
0x52,'"',
0x54,'{',
0x55,'+',
0x5b,'}',
0x5d,'|',
0x61,'>',
0x69,'1',
0x6b,'4',
0x6c,'7',
0x70,'0',
0x71,'.',
0x72,'2',
0x73,'5',
0x74,'6',
0x75,'8',
0x79,'+',
0x7a,'3',
0x7b,'-',
0x7c,'*',
0x7d,'9',
0,0
};
PS2_KEY_STATUS PS2KeyStatus;
unsigned char g_KeyAsiic;
/************************************************************************
*名稱: void DelayMS(unsigned int uiMS)
*功能: 延時nms
*參數: 無
*返回: 無
************************************************************************/
void DelayMS(unsigned int wMS)
{
while(wMS--)
{
_delay_loop_2(2000); // 延時1ms(粗略)
}
}
/*************************************************************************
*名稱: void PORT_Init(void)
*功能: 端口初始化
*參數: 無
*返回: 無
*************************************************************************/
void PORT_Init(void)
{
PORTD |= (1 << PD1) | ( 1 << PD2) | ( 1 << PD3);
DDRD |= (1 << PD1); //PD1胔出胔出高電平,PD2胔入帶上拉
PORTC |= (1 << PC0); //PC0胔入帶上拉
}
void INT0_Init(void)
{
EICRA |= (1 << ISC01); //INT0下降沿觸發
EIMSK |= (1 << INT0); //使能INT0中斷
}
/************************************************************************
*名稱: void USART_Init(void)
*功能: 串口初始化
*參數: 無
*返回: 無
************************************************************************/
void USART_Init(void)
{
UCSR0C = (1 << UCSZ01)|(1 << UCSZ00);
//異步操作,8位數據,無奇偶校驗位,一個停止位
UBRR0L = (F_CPU / BAUDRATE / 16 - 1) % 256; //設瞞波特率
UBRR0H = (F_CPU / BAUDRATE / 16 - 1) / 256;
UCSR0B = (1 << RXCIE0)|(1 << RXEN0)|(1 << TXEN0);
//使能接收中斷,使能接收,使能發送
}
/************************************************************************
*名稱: void USART_PutChar(unsigned char bTxData)
*功能: 向串口發送一個字符
*參數: bTxData 要發送的字符
*返回: 無
************************************************************************/
void USART_PutChar(unsigned char bData)
{
while(!(UCSR0A&(1 << UDRE0))); //發送緩沖器是否准備就緒
UDR0 = bData; //將要發數據送數據緩沖器
}
/************************************************************************
*名稱: void USART_PutString(unsigned char *bString)
*功能: 向串口發送字反
*參數: *pbStringbString 要發送的字符串
*返回: 無
************************************************************************/
void USART_PutString(unsigned char *pbString)
{
while (*pbString)
{
USART_PutChar(*pbString++);
}
}
/************************************************************************
*名稱: unsigned char PS2_KeyDeCode(unsigned char bKeyCode)
*功能: PS2鍵盤解碼程序
*參數: bKeyCode 鍵盤碼
*返回: 按鍵的ASIIC碼
************************************************************************/
unsigned char PS2_KeyDeCode(unsigned char bKeyCode)
{
unsigned char i;
if (!PS2KeyStatus.bBreakFlag)//通碼
{
switch (bKeyCode)//開始翻譯掃描碼
{
case 0xF0: //鍵盤釋放隨後的一個字節是斷碼
{
PS2KeyStatus.bBreakFlag = 1;//斷碼標志瞞位
break;
}
case 0x12: //左shift鍵按下
{
PS2KeyStatus.bShiftFlag = 1; //shift標志瞞位
break;
}
case 0x59: //右shift鍵按下
{
PS2KeyStatus.bShiftFlag = 1; //shift標志瞞位
break;
}
default:
{
PS2KeyStatus.bBreakFlag = FALSE;
if(!PS2KeyStatus.bShiftFlag) //如果shift鍵沒有按下
{
for(i = 0; i < 65; i++)//查表找按鍵ASIIC碼
{
if(pgm_read_byte(PS2CodeUnShift[i]) == bKeyCode)
{
PS2KeyStatus.bKeyAsiic =
pgm_read_byte(PS2CodeUnShift[i] + 1);
PS2KeyStatus.bKeyNewFlag = TRUE;
break;
}
}
}
else //如果shift鍵按下
{
for(i=0; i < 65; i++)//查表找按鍵ASIIC碼
{
if(pgm_read_byte(PS2CodeShift[i]) == bKeyCode)
{
PS2KeyStatus.bKeyAsiic =
pgm_read_byte(PS2CodeShift[i] + 1);
PS2KeyStatus.bKeyNewFlag = TRUE;
break;
}
}
}
break;
}
}
}
else //斷碼
{
PS2KeyStatus.bBreakFlag = 0; //將斷碼標志復位
switch (bKeyCode) //檢測shift鍵釋放
{
case 0x12 : //左shift鍵
PS2KeyStatus.bShiftFlag = 0;
break;
case 0x59 : //右shift鍵
PS2KeyStatus.bShiftFlag = 0;
break;
default:
break;
}
}
}
/************************************************************************
*名稱: ISR(INT0_vect )
*功能: INT0中斷服務程序
*參數: 無
*返回: 無
*************************************************************************/
ISR(INT0_vect )
{
static char bOddParity = 0;
static unsigned char bBitCounter = 0; //鍵盤幀位計數
static unsigned char bKeyCode;
bBitCounter++;
if(bBitCounter == 1)//START位
{
if(PS2_DB_INPUT != 0)
{
bBitCounter = 0;
}
return;
}
else if(bBitCounter > 1 && bBitCounter < 10) //接收8位數據
{
bKeyCode >>= 1;
if(PS2_DB_INPUT)
{
bKeyCode |= 0x80;
bOddParity++;
}
return;
}
else if(bBitCounter == 10)
{
if(bKeyCode ^ (bOddParity & 0x01)) //奇校驗正確
{
PS2_KeyDeCode(bKeyCode); //解碼
}
else
{
bBitCounter = 0;
}
return;
}
else if(bBitCounter == 11) //11位數據接收完畢
{
bBitCounter = 0;
bOddParity = 0;
return;
}
}
/************************************************************************
*名稱: unsigned char PS2_KeyScan(void)
*功能: PS2鍵盤掃描程序
*參數: 無
*返回: 新按下按鍵的ASIIC碼
*************************************************************************/
unsigned char PS2_KeyScan(void)
{
unsigned char temp;
if(PS2KeyStatus.bKeyNewFlag == TRUE) //如果有新按鍵按下
{
PS2KeyStatus.bKeyNewFlag = FALSE; //復位新按鍵標志
if(PS2KeyStatus.bBreakFlag == FALSE) //如果不是斷碼
{
temp = PS2KeyStatus.bKeyAsiic;
PS2KeyStatus.bKeyAsiic = NULL;
return temp;
}
}
return NULL;
}
int main(void)
{
PORT_Init();
INT0_Init();
USART_Init();
PS2KeyStatus.bKeyNewFlag = FALSE; //初始化按鍵狀態結構伐變量
PS2KeyStatus.bBreakFlag = FALSE;
PS2KeyStatus.bShiftFlag = FALSE;
PS2KeyStatus.bKeyAsiic = NULL;
sei();
while(1)
{
g_KeyAsiic = PS2_KeyScan(); //獲取PS2按鍵ASIIC
if(g_KeyAsiic != NULL) //如果有按鍵按下
{
USART_PutChar(g_KeyAsiic); //像串口放松按鍵ASCCI
}
}
}
全站熱搜
留言列表