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/n4altnw

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 ledState = HIGH;            // the current state of the output pin
int buttonState = 0;              // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin

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);
  // set initial LED state
  digitalWrite(ledPin, ledState);
}

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(){
if (reading != lastButtonState){
//reset bounce timer
lastDebounceTime = millis();
}
if ((Millis() - lastDebounceTime) > debounceDelay) {
// if the button state has changed
if (reading != buttonState){
buttonState  = reading;
if (buttonState == HIGH){
ledState = !ledState;
}
}
}
}
and change the loop code to:

//set the led
digitalWrite(ledPin, ledState);
//save the reading, 
//next time through the loop,
// it will be the lastButtonState:
lastButtonState = reading;


and add the following above the setup part of the sketch:

long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // debounce time, increase if output flickers

Follow for more info on Interrupts and INPUT_PULLUP.