PS/2 Keyboard Interface

About

The class allows any IO pins to be used. Relies on default pull-up resistors having not been disabled.
Reads the Scan Code from a PS2 Keyboard and converts most characters into ASCII Code, a list of which to be attached.
Doesn't support host to keyboard commands i.e. - no CAPS LOCK Status LEDS

Most character keys have been covered and all non-character keys return the make code, with the exception of non-character keys with a scan code of more than one byte, which return the second byte and raise a flag to say that there are two bytes. Since the first byte is always 0xE0 the flag is E0flag

Pinout

Looking into end of the plug:


          nc --->   o  o   <--- clk
 
       +5V --->   o      o   <--- GND
                     ||
         nc --->   o || o   <--- data

The Code

#include <mbed.h>

Digital ps2clk(54);
Digital ps2din(53);
static const unsigned char ps2KeyMap[] = {
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '`', ' ', // 00-0F
    ' ', ' ', ' ', ' ', ' ', 'Q', '1', ' ', ' ', ' ', 'Z', 'S', 'A', 'W', '2', ' ', // 10-1F
    ' ', 'C', 'X', 'D', 'E', '4', '3', ' ', ' ', ' ', 'V', 'F', 'T', 'R', '5', ' ', // 20-2F
    ' ', 'N', 'B', 'H', 'G', 'Y', '6', ' ', ' ', ' ', 'M', 'J', 'U', '7', '8', ' ', // 30-3F
    ' ', ',', 'K', 'I', 'O', '0', '9', ' ', ' ', '.', '/', 'L', ';', 'P', '-', ' ', // 40-4F
    ' ', ' ','\'', ' ', '[', '=', ' ', ' ', ' ', ' ', ' ', ']', ' ','\\', ' ', ' ', // 50-5F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 60-6F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 70-7F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 80-8F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 90-9F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // A0-AF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // B0-BF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // C0-CF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // D0-DF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // E0-EF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // F0-FF
};
unsigned char ps2GetKey(void)
{
    unsigned int buf;
    int i;
    buf = 0;
    ps2clk = 0;
    ps2din.direction(0);
    ps2clk.direction(0);
    for(i=0;i<11;i++) {
        while(ps2clk);
        while(!ps2clk);
        buf = buf >> 1;
        buf |= ps2din ? 512 : 0;
    }
    ps2clk.direction(1);
    buf &= 0xFF;
    return (unsigned char)buf;
}
int main(void)
{
    printf("\n\rPS2 Keyboard:");
    while(1) {
        unsigned char c;
skip_break:
        c = ps2GetKey();
        if(c == 0xF0) {
            c = ps2GetKey();
            goto skip_break;
        }
        printf("%c", ps2KeyMap[c]);
    }
    return 0;
}

Extension

My task was to improve the PS2 Keyboard Interface by manipulating the data to produce a single ASCII character for every one typed on the keyboard. Also the CAPS LOCK key and the SHIFT key were to function as on a keyboard, so:

EFFECT ON LETTERSEFFECT ON OTHER SYMBOL
NO CAPSNO SHIFTLOWERCASEBOTTOM SYMBOL
NO CAPSSHIFTUPPERCASETOP SYMBOL
CAPSNO SHIFTUPPERCASEBOTTOM SYMBOL
CAPSSHIFTLOWERCASETOP SYMBOL

My early versions of the code were developed in the main.cpp but later on I created a class PS2ASCII. The header file and CPP are downloadable from the SVN. In order for a PS2 Keyboard to fully function two other header files and CPPs are in the trunc file for download.

The Initial Concept

#include "mbed.h"
#include "PS2Kbd.h"
#include "MobileLCD.h"

PS2Kbd kbd(28, 27);
Serial pc (USBTX,USBRX);
MobileLCD lcd(5, 6, 7, 8, 9);
DigitalOut Led(LED1);
bool caps = false;
bool shift = false;
static const unsigned char shift_on[] = {
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '`', ' ', // 00-0F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 10-1F
    ' ', 0x21, 0x22, '~', 0x24, 0x25, 0x26, '@', 0x28, 0x29, 0x30, 0x31, '<', '_', '>', '?', // 20-2F
    ')', '!', '\"', 0x9C, '$', '%', '^', '&', '*', '(', ' ', ':', ' ', '+', ' ', ' ', // 30-3F
    0xAA, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', // 40-6F
    'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', ' ', ' ', // 50-7F
    ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', // 60-4F
    'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', ' ', ' ', ' ', ' ', // 70-5F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 80-8F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 90-9F
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // A0-AF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // B0-BF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // C0-CF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // D0-DF
    ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // E0-EF
    NULL, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // F0-FF
};
int main()
{
        lcd.background(0x1E1CCD);                   //screen colour - some shade of blue
        lcd.cls();
    while(1)
    {
        unsigned char keypress = kbd.rd();      //code in

        if(keypress == 0xE0)                    //is it a special E0 key?
        {
            keypress = kbd.rd();                //next byte in
            if(keypress == NULL)                //is is a break code?
            {
                keypress = kbd.rd();            //if so chew it up and back to start
                continue;
            }
            lcd.printf("E0 ");                  //tell us that it is
            lcd.printf("%d ", keypress);
            continue;
        }
        if((keypress == 0x12) || (keypress == 0x59))                    //SHIFT pressed?
        {
            shift = true;
            continue;
        }
        if(keypress == NULL)                    //gets rid of byte 1 of break code
        {
            keypress = kbd.rd();                //byte 2 of break code in

            switch (keypress)
            {
                case 0x12:
                    shift = false;              //if SHIFT released turn shift off
                    continue;
                case 0x59:
                    shift = false;
                    continue;
                default:
                    continue;
            }
        }
        switch (keypress)
        {
            case 0x1B:                          //the ESC key
                lcd.cls();
                continue;
            case 0x5A:
                lcd.newline();                  //the RETURN key
                continue;
            case 0x58:
                caps = !caps;                   //the CAPS LOCK key
                continue;
            default:
                break;
        }
        unsigned char last_keypress = keypress;
        if(shift == true)                       //if SHIFT is pressed take shifted character
        {
            last_keypress = shift_on[keypress];
        }
        if((keypress >= 97)&&(keypress <= 127))     //is character a letter?
        {
            if((caps == true)&&(shift == false))
            {
                last_keypress = shift_on[keypress]; //if caps is on shift the letter up
            }
            if((caps == true)&&(shift == true))     //if caps and shift are on shift the letter back down
            {
                last_keypress = shift_on[last_keypress];
            }
        }
        lcd.printf("%c", last_keypress);
        wait(0.03);
     }
}

This program looks at the character received in ASCII and according to the CAPS LOCK/SHIFT key table above, shifts each character up or down via the array at the top of the program. This program was intended for displaying a charcter on a MOD-NOKIA-6610 LCD Screen availiable from [ http://www.coolcomponents.co.uk/catalog/product_info.php?cPath=24&products_id=147 ] source:/PS2Keyboard/doc/DSCF0341.jpg

The End Product

The main is a lot shorter with the new PS2ASCII class.

#include "mbed.h"
#include "PS2Kbd.h"
#include "MobileLCD.h"
#include "PS2ASCII.h"

MobileLCD lcd(5, 6, 7, 8, 9);
PS2ASCII myKeyboard(28, 26);
DigitalOut LED(LED1);
int main()
{
        lcd.background(0x000000);                   //screen colour - black
        lcd.cls();                                  //clear screen

        while(1) {
        unsigned char symbol = myKeyboard.getChar();
        if(symbol == 0x1B)                          //clear screen function
        {
            lcd.cls();
            continue;
        }
        if(myKeyboard.E0flag() == true)             //is the make code one or two bytes long?
        {
            lcd.printf(" E0 ");
            lcd.printf("%c ", symbol);
            continue;
        }
        lcd.printf("%c", symbol);
        }
 }
source:/PS2Keyboard/doc/DSCF0342.jpg
CodePhoto

This Program is configured to print a character onto the Nokia LCD and if a function key is pressed of more than one byte the LCD displays E0 space scan code.

To Do

Convert to use a peripheral and fuse with mbedVGA code!

enjoy!
Daniel.