General

I needed keyboard support for a project where I could plug a keyboard in to a live Arduino based box so that I could monitor things and change parameters stored in eeprom but without having to use a computer or turning off the box.

Plugging/unplugging the keyboard live was my main problem with previous PS2Keyboard libraries but I also wanted shifted keys to work properly with the caps lock light too.

The solution I came up with is based on PS2Keyboard but modified extensively. I've gone for functionality rather than small code size so this version will take up about 2500 bytes of code space. I also went for ease of use at the calling level, hence shifting and caps lock is all done within the library. <alt> and <ctrl> are also handled but the user has to "read" these as extra information and use them themselves.

Heres an example sketch:

#include <PS2Keyboard.h>

// Simple test program for new PS2Keyboard library
// Connect a PS2 keyboard to pins 3 & 4 (CLK and DATA respectively) and supply 5V to the keyboard
// For examples, see here: http://playground.arduino.cc/ComponentLib/Ps2mouse
// or                here: http://www.beyondlogic.org/keyboard/keybrd.htm
// That second article is a great place to start if you want to understand whats going on
//
// When you've compiled the code and uploaded it to the board, start a serial monitor at
// 9600bd.  Then press keys on your PS2 keyboard (the one connected to Arduino, not the one
// connected to your computer!) Try using <shift>, <ctrl> and <alt> keys
// and check that the caps_lock key sets the caps_lock light.
// Pressing <esc> key should reset the keyboard and you should see all 3 lights go on briefly.

#define KBD_CLK_PIN  3
#define KBD_DATA_PIN 4

PS2Keyboard keyboard;

void setup() {
  keyboard.begin(KBD_DATA_PIN);

  Serial.begin(9600);
  delay(1000);
}

#define is_printable(c) (!(c&0x80))   // don't print if top bit is set

void loop() {

  if(keyboard.available()) {

    // reading the "extra" bits is optional
    byte   extra = keyboard.read_extra(); // must read extra before reading the character byte
    byte       c = keyboard.read();

    boolean ctrl = extra & 1;  // <ctrl> is bit 0
    boolean  alt = extra & 2;  //  <alt> is bit 1

    if (ctrl) Serial.print('^');
    if (alt)  Serial.print('_');

    if      (c==PS2_KC_UP)      Serial.print("up\n");
    else if (c==PS2_KC_DOWN)    Serial.print("down\n");
    else if (c==PS2_KC_BKSP)    Serial.print("backspace\n");
    else if (c==PS2_KC_ESC)   { Serial.print("escape and reset\n"); keyboard.reset(); }
    else if ( is_printable(c) ) Serial.print(c);   // don't print any untrapped special characters
  } 
}

and here's the code (sorry not bundled up into a library I'm afraid - haven't tried that yet. I just overwrote the PS2Keyboard.cpp and PS2Keyboard.h files with my own version.

PS2Keyboard.cpp

PS2Keyboard.h

  ** Updated for Arduino 17 & brought clockPin into the library & added a keyboardLites blocker 
  *** & added [;:] + ['"] -- couldn't get [\|] to work tho'
  ** compiled into a library
  ** allen joslin 05/17/10

http://code.google.com/p/arduino-ajoslin/

here's some sample code using a SparkFunSerLCD object to echo the output from a PS2Keyboard object


// author: allen @joslin .net

#include <stdlib.h> // for malloc and free

// eyes-on memory allocation 

uint8_t * heapptr, * stackptr;
void check_mem() {
	stackptr = (uint8_t *)malloc(4);  // use stackptr temporarily
	heapptr = stackptr;               // save value of heap pointer
	free(stackptr);      // free up the memory again (sets stackptr to 0)
	stackptr =  (uint8_t *)(SP);      // save value of stack pointer
}

void print_mem() { check_mem(); Serial.print(" mem:"); Serial.println((stackptr-heapptr),DEC); }

// ---------------------------------------------

void * operator new(size_t size) {  return malloc(size); }
void operator delete(void * ptr) {  if (ptr != NULL) { free(ptr); } }

// ---------------------------------------------

// Object PS2Keyboard :: this object is in charge of a PS2 keyboard

#include <PS2Keyboard.h>

// ---------------------------------------------

// Object SparkFunSerLCD :: this object is in charge of an LCD panel
//        these are 1-based devices, 1st cell is [1,1]

#include <SoftwareSerial.h>
#include <SparkFunSerLCD.h>

// --------------------------------------------

// Object LCDEcho :: this object is in charge of echoing keypresses from 
//     a PS2Keyboard to a SparkFunSerLCD

class LCDEcho {
private:
	int numRows, numCols, col, row;
	int lcdPin;

public:
	SparkFunSerLCD* lcd;
	PS2Keyboard* keys;

	LCDEcho ( int _data, int _clock, bool _lites, int _lcd, int _rows, int _cols  ) {
		keys = new PS2Keyboard(_data,_clock,_lites);
		lcd = new SparkFunSerLCD(_lcd,_rows,_cols);
		numRows = _rows; numCols = _cols; 
	}

	void start () {
		reset(); 
		lcd->setup(); 
		keys->begin();
	}

	void reset () {
		row = col = 1;
		lcd->empty();
	}

	inline bool available () { return keys->available(); }
	inline byte read () { return keys->read(); }

	void echo ( byte dat ) {

		if (dat < 0x80) {
			col++; lcd->at(row,col,(char)dat);
			if (col > numCols) {
				col = 1; 
				row++;
			}
		}

		if(dat == PS2_KC_BKSP) {
			lcd->at(row,col,' ');
			col--;
			if (col < 0) {
				col = numCols; 
				row--;
			}
		}

		if(dat == PS2_KC_ESC) {
			row = col = 1;
			reset();
		}

	}

};

// --------------------------------------------
// setup the testbed

LCDEcho* lcdEcho;

void setup () {
	Serial.begin(9600); 

	// LCDEcho ( int _PS2data, int _PS2clock, bool _PS2lites, int _lcdPin, int _rows, int _cols  ) 
	lcdEcho = new LCDEcho(2,3,false,10,2,16);

	lcdEcho->start();
}

// run the installation
void loop () {

	if (lcdEcho->available()) { 
		lcdEcho->echo(lcdEcho->read());
	}
}

// done 
// ---------------------------------------------------


this page has the pin outs for the ps2 receptacle http://playground.arduino.cc/ComponentLib/Ps2mouse

this page has a schematic http://www.practicalarduino.com/projects/ps2-keyboard-or-mouse

Share