Sunday, June 3, 2012

Arduino as RFID Reader to HID Text Input

RFID is an interesting technology with a lot of potential uses for Arduino projects. Parallax RFID tag readers are a great RFID solution for use with Arduino because they're so simple to implement, plus they only need two pins to interface with Arduino. One pin activates the reader and the other transmits the code via serial connection. Radioshack has the Parallax brand readers on clearance. My local Radioshack actually gave me some for free because they couldn't find them in the system. Once I had a reader and tags, the first thing I did was use the software serial library to relay the RFID tags via serial to the computer. Receiving the tag via the serial monitor was interesting, but fairly limited in utility. I decided I wanted to relay the tag code as keyboard input so that it could be used for something such as a password, but that required the Arduino to act as a USB human interface device (HID).

I had a little trouble figuring out how to make the Arduino act as a keyboard so I decided to share what I've learned by posting an Arduino as HID device tutorial below. Check out the demo and tutorial below.

Demonstration:





Using Parallax RFID Tag Reader with Arduino:

The first thing I wanted to do was read in the tag codes via serial. The Arduino site has some great examples on how to use the Parallax RFID reader to do just that.

Arduino as Keyboard / HID:


Intro:
When I began to research using the Arduino Uno as a keyboard, I was surprised to learn that the chip that handles the USB connection for the Arduino Uno is actually a re-programmable Atmega16U2 or 8U2 (depending on Arduino Uno version) setup as a virtual USB serial device. The Arduino resets whenever a serial connection is initiated. During each reset, the Arduino bootloader checks to see if a new program is being transmitted to it via serial. It then proceeds to the setup function and finally the loop function of the uploaded code. The 16u2 or 8u2 used for USB on the Uno can be programmed to act as several different HIDs that receives commands from the main chip via serial instead of just relaying the serial connection over USB.

Reprogramming Atmega16u2 or 8u2:
Thankfully, the hard work of programming the USB connected chip to act as a HID has been accomplished by others. All you need to do is download the appropriate hex files from this site and flash it to the USB chip using a program from Atmel called FLIP. The only trick is that it needs to be in DFU mode. Just short the two pins identified in the image to enter DFU mode. The Arduino USB connection should re-enumerate as a different device as soon as you short the pins highlighted on the left.

One small word of warning: The downside of turning the Arduino into a human interface device is that the Arduino cannot be programmed using the Arduino IDE unless the USB connected Atmega is programmed to be a serial relay again. This page has more details about DFU mode and a link to the hex file that returns the Arduino to its regular state. The steps for using FLIP are displayed below:

 After entering DFU mode (see above), select the USB connection.
Select the HEX file that you want to load. This  should be Arduino-keyboard-0.3.hex or Arduino-usbserial-atmega16u2-Uno-Rev3.hex for example. These HEX files are pre-compiled instructions for the microcontroller that runs the USB connection. Thanks to the Arduino community for making this so easy by providing these files!
Once you hit run, these icons should turn green if everything worked. Once this is complete, disconnect and reconnect the Arduino to leave DFU mode and enter normal or HID operation.











That's all there is to it. If you have any question or you have any tips or corrections, please comment.

Arduino Code:


Here's the code I utilized in the demo. Remember, to program the Arduino with the IDE before using FLIP to make the Arduino show up as keyboard.

// Reads RFID Tag from Parallax RFID reader using software serial
// sends TAG code via serial to ATMEGA16u2 programmed to act as
// a USB HID to send the TAG as keyboard presses

#include <SoftwareSerial.h>
SoftwareSerial mySerial(6, 7); //software serial for rfid reader

uint8_t buf[8] = { 0 }; /* Keyboard report buffer */

int read = 0;

int  val = 0; 
char code[10]; 
int bytesread = 0; 

const int buttonPin = 3; //Activation button

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

// These aren't really necessary but the rest are available 
// Use this file as a guide for other keystrokes  
// http://www.usb.org/developers/devclass_docs/Hut1_11.pdf
#define KEY_LEFT_CTRL 0x01
#define KEY_LEFT_SHIFT 0x02
#define KEY_RIGHT_CTRL 0x10
#define KEY_RIGHT_SHIFT 0x20

void setup()  
{
  Serial.begin(9600); //connection between chips
  delay(200);

  mySerial.begin(2400);   // set the data rate for the SoftwareSerial port 
  pinMode(2,OUTPUT);      // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin 
  digitalWrite(2, HIGH);  // Turn off reader
  pinMode(buttonPin, INPUT);  // Set the input pin for the activation button
}

// Function to send char[] to computer as keyboard presses
// This section is based on http://hunt.net.nz/users/darran/weblog/b3029/Arduino_UNO_Keyboard_HID_version_03.html
// Modified to handle numerals 
void type(char *str) 
{
    char *chp = str;
    delay(100);
    while (*chp) {
     
 if ((*chp >= 'a') && (*chp <= 'z')) {
     buf[2] = *chp - 'a' + 4; //Converts from char to usb code from HUT1_11.pdf else if ((*chp >= 'A') && (*chp <= 'Z')) {
     buf[0] = KEY_LEFT_SHIFT; /* Caps */
     buf[2] = *chp - 'A' + 4; //Converts from char to usb code from HUT1_11.pdf else if ((*chp >= '0') && (*chp <= '9')) {
     buf[2] = *chp - '0' + 30; //Converts from char to usb code from HUT1_11.pdf else {
     switch (*chp) {
     case ' ':
      buf[2] = 0x2c; // Space
  break;
     default:
         /* Character not handled. To do: add rest of chars from HUT1_11.pdf */
  //buf[2] = 0x37; // Period
  break;
     }
 }

 Serial.write(buf, 8); // Send keypress
 buf[0] = 0;
 buf[2] = 0;
 Serial.write(buf, 8); // Release key
 chp++;
    }
}

void loop() { 
  
  // Turns the RFID reader on
  int reading = digitalRead(buttonPin); // check button status
  if (((millis() - lastDebounceTime) > debounceDelay ) && (reading == HIGH) && (read==0))  {
      digitalWrite(2, LOW);                  // Activate the RFID reader
      lastDebounceTime = millis();
      //Serial.println("Reader on");
      read = 1;
      
  }
  
  // Reads the code if the button has been pressed
  // Most of this chunk is from http://arduino.cc/playground/Learning/PRFID
  if((mySerial.available() > 0) && (read==1)) {          // if data available from reader 
    if((val = mySerial.read()) == 10) {  // check for header 
      bytesread = 0;                     // reset bytesread
      while(bytesread<10) {              // read 10 digit code 
        if( mySerial.available() > 0) { 
          val = mySerial.read(); 
          if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading 
            break;                       // stop reading 
          } 
          code[bytesread] = val;         // add the digit           
          bytesread++;                   // ready to read next digit  
        } 
      } 
      if(bytesread == 10) {               // if 10 digit read is complete 
        type(code);                       // send code via simulated HID
      } 
      bytesread = 0; 
      digitalWrite(2, HIGH);              // deactivate the RFID reader until the button is pressend again
      read = 0; 
    } 
  } 
} 

Thanks to the Arduino community for all the great info I found that made this project so easy! I would like to specifically thank darran from hunt.net.nz for sharing his Arduino as HID hex files used in this project. Please post any comments or questions below.


7 comments:

  1. Hi, I have something that might interest you: http://www.frank-zhao.com/cache/usnoobie_rfid_keyboard.php

    ReplyDelete
  2. Thanks for sharing excellent information. Your web-site is very cool.

    ReplyDelete
  3. RFID reader is undoubtedly a very interesting and useful technology. Well-written post!

    ReplyDelete
  4. Very nice and helpful information has been given in this article. I like the way you explain the things. Keep posting. Thanks..

    Best RFID Solutions Provider Company

    ReplyDelete
  5. Interesting and amazing how your post is! It Is Useful and helpful for me That I like it very much, and I am looking forward to Hearing from your next.. rfid tags

    ReplyDelete
  6. Can i do this with Arduino UNO R3 Mega328P? Please send me how? robsonandrade@hotmail.com

    ReplyDelete