Saturday, September 28, 2013

Arduino Keyboard Shield - Part 3

The PS/2 Keyboard Smart Shield prototype is operational!

Now on Instructables!

This is Part 3 in the series.

The Atmel 328P DIY Arduino is reading a PS/2 Keyboard, converting the scan codes to characters, and transmitting the characters to the host Arduino. This removes the burden (memory and cpu cycles) from the host, as it only has to read in characters on a serial port. You can download the code (and the library) from

http://tinyurl.com/PS2KybdArduino

This is our first of our "SmartShields". Stay tuned for other intelligent shields!

To help us get this shield to production, please order this prototype interface as shown (keyboard not included) for $30


Arduino Keyboard Shield - Part 2

Continuing from Arduino Keyboard Shield - Part 1, we now have keyboard input from a PS/2 keyboard displaying in the serial monitor. The next step will be building the Smart Shield, which contains a ATMEL 328P running the following code, and the keyboard interface, and sends the received data to the main Arduino.

You will need to download the library and run the included example "Simple_Test". We changed the Interrupt and Data numbers in the example to 3 & 4 respectively.

/*  PS2Keyboard library example

  PS2Keyboard now requries both pins specified for begin()

  keyboard.begin(data_pin, irq_pin);

  Valid irq pins:
     Arduino:      2, 3
     Arduino Mega: 2, 3, 18, 19, 20, 21
     Teensy 1.0:   0, 1, 2, 3, 4, 6, 7, 16
     Teensy 2.0:   5, 6, 7, 8
     Teensy++ 1.0: 0, 1, 2, 3, 18, 19, 36, 37
     Teensy++ 2.0: 0, 1, 2, 3, 18, 19, 36, 37
     Sanguino:     2, 10, 11

  for more information you can read the original wiki in arduino.cc
  at http://www.arduino.cc/playground/Main/PS2Keyboard
  or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html

  Like the Original library and example this is under LGPL license.

  Modified by Cuninganreset@gmail.com on 2010-03-22
  Modified by Paul Stoffregen June 2010
*/
 
#include "PS2Keyboard.h"

const int DataPin = 4;
const int IRQpin =  3;

PS2Keyboard keyboard;

void setup() {
  delay(1000);
  keyboard.begin(DataPin, IRQpin);
  Serial.begin(9600);
  Serial.println("Keyboard Test:");
}

void loop() {
  if (keyboard.available()) {
 
    // read the next key
    char c = keyboard.read();
 
    // check for some of the special keys
    if (c == PS2_ENTER) {
      Serial.println();
    } else if (c == PS2_TAB) {
      Serial.print("[Tab]");
    } else if (c == PS2_ESC) {
      Serial.print("[ESC]");
    } else if (c == PS2_PAGEDOWN) {
      Serial.print("[PgDn]");
    } else if (c == PS2_PAGEUP) {
      Serial.print("[PgUp]");
    } else if (c == PS2_LEFTARROW) {
      Serial.print("[Left]");
    } else if (c == PS2_RIGHTARROW) {
      Serial.print("[Right]");
    } else if (c == PS2_UPARROW) {
      Serial.print("[Up]");
    } else if (c == PS2_DOWNARROW) {
      Serial.print("[Down]");
    } else if (c == PS2_DELETE) {
      Serial.print("[Del]");
    } else {
   
      // otherwise, just print all normal characters
      Serial.print(c);
    }
  }
}


Monday, September 23, 2013

Interrupts, the easy way

Many folks starting out in microcontrollers do not know what interrupts are, or are intimidated by them. Today I hope to shed some light on this easy to use, and useful function.

There are two ways to detect if an event has happened, polling, and interrupts. If you are expecting someone to come to your front door, you can get up every few minutes to look out the window (polling), or you can be busy cleaning your house until the doorbell rings (interrupts).

The most common for beginners is polling. In a loop, I check to see if an input is high, or low. Two disadvantages of this method are 1) I might miss an event if I'm busy doing something else, 2) I'm busy checking for the event, and that slows down my other processes.

Interrupts allow me to process a lot of other stuff, and then the interrupt will notify me when the event being monitored happens.

Let's look at a scenario:

I have a push button (doorbell) connected to D2. I have a LED connected to D13. I want to know when someone is at the door, and light the LED when the button is pushed. The polling method would look like this:

// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);    
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);  
}

void loop(){
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is LOW:
  if (buttonState == LOW) {  
    // turn LED on:  
    digitalWrite(ledPin, HIGH);
  }
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW);
  }
}

Now, let's look at the interrupt version of this sketch, Since the event is short lived, we will toggle the state of the LED each time it's pushed (straying from our doorbell example), this would be ideal for monitoring rpm or other fast moving events, by counting the number of triggers per unit of time:

/*
  Button

 Turns on and off a light emitting diode(LED) connected to digital
 pin 13, when pressing a pushbutton attached to pin 2.


 The circuit:
 * LED attached from pin 13 to ground
 * pushbutton attached to pin 2 from Gnd
we are using pinMode INPUT_PULLUP, so no pull up or pull down resistor needed.
INPUT_PULLUP is the same as adding an external pullup resistor


 * Note: on most Arduinos there is already an LED on the board
 attached to pin 13. We are using the onboard LED for our example.
If you use an external on any other pin, you will need a resistor.


 */

// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);  
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT_PULLUP);
  // set up the interrupt on pin 2, call the routine,
  // and set the action that triggers the call
  attachInterrupt(0, blink, FALLING);
}

void loop()
{
 digitalWrite(ledPin, buttonState);
}

void blink()
{
  buttonState = !buttonState;
}

Now, we notice that effect is erratic. sometimes the button blinks, sometimes it stays steady. This is due to button bounce. The contacts don't make a single state change, they connect / disconnect quite a few times aver a very short time. We need to debounce the button.

change the void blink() function to the following:

void blink()
{
static unsigned long lastMillis = 0;
unsigned long newMillis = millis();
if (newMillis - lastMillis < 50){
}
else{
  buttonState = !buttonState;
  lastMillis = newMillis;
}
}

Follow for more info on Interrupts and INPUT_PULLUP.