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
                }
            }
    }



arrow
arrow
    全站熱搜

    xiaolabaDIY 發表在 痞客邦 留言(0) 人氣()