Project

Build Your Own RFID Technology Using an Arduino MEGA

July 20, 2016 by Joseph Corleto

In this article, we are going to learn some basics about RFID technology and use an Arduino MEGA to a play around with a popular RFID module, the ID12LA.

In this article, we are going to learn some basics about RFID technology and use an Arduino MEGA to a play around with a popular RFID module, the ID12LA.

RFID stands for Radio Frequency IDentification. If you haven’t noticed yet, it is found in many places. This technology is near you right now!

RFID technology is commonly found in hotels, offices, banks, stores, etc. RFID chips are even implanted in pets to make sure that they can be identified and returned home if lost. It is often compared to a barcode. But even if it has the same use as a barcode, the two differ in a few ways.

In this article, we are going to learn some basics about RFID technology and use an Arduino MEGA to a play around with a popular RFID module, the ID12LA. You will be surprised by how easy it will be to incorporate this technology into your next electronics project! 

 

The ID12LA. Image courtesy of Sparkfun.

BOM

Hardware

  • Arduino MEGA
    • You don't have to use a MEGA, but this will do!
  • ID12LA
  • ID12LA Breakout PCB
    • The pins to the ID12LA are a bit weird so I suggest the breakout PCB from Sparkfun or any other reputable dealer.
  • Small Breadboard
  • Some jumper wires
  • Solder and soldering iron

Software

  • Arduino IDE

Theory

Before we can start any kind of software or hardware planning, it is essential to have an understanding of the very basics of RFID.

In any RFID system, there will be a device that will have information, typically called a tag or transponder, and another device that will “look” or “sense” this information, typically called a reader or interrogator. Both components will need to have their own antenna to communicate and, depending on the type of RFID technology, they can exchange information one or both ways.

To understand this better, we need to understand the two distinctly different types of RFID technology: passive and active.

 

Passive RFID

Let’s start with passive. In a passive system, the tag consists of an antenna and circuitry to house a unique code. But there is no power source (no battery), so how does the circuitry inside get powered?

The answer lies in the reader. In a passive RFID system, the reader will have an antenna that will emit RF energy that will induce a current in the tag’s circuitry. So whenever the tag is moving through the reader’s electromagnetic field, it gets powered and then immediately broadcasts its unique code. At the same time, the reader is also listening for this code.

At what range does all this happen? It depends on the reader and tag, but it is largely dependent on the frequency on which the code is broadcasted. The three main frequencies for passive RFID are:

  • Low frequency: ~125 kHz. Typically has a range of a few centimeters
  • High frequency: 13.56 MHz. Has a range of up to a meter
  • Ultra-high frequency: ~865 MHz. Has a range of about 30 meters

With all this being said, the ID12LA in our project is a passive type reader that consists of a built-in antenna and circuitry that can decode the tag and spit out serial data that our Arduino can understand. It is also 125 kHz which means we need tags that can be interrogated on that frequency.

Passive RFID may seem like it would have its shortcomings due to its short read range but these systems are generally inexpensive. Also, since the tags have no batteries, they can last a long time without service.

Below is a type of 125 kHz, passive tag that the ID12LA can interrogate:

RFID key tags. Image courtesy of RFIDTEK.

Active RFID

Now for active RFID.

As you might have guessed, these tags are always powered and thus have an onboard battery to transmit their code.

Because of this, along with the option of operating at either 433 MHz or 915 MHz, they have a very long read range—up to a couple of hundred meters! And since they have onboard batteries, they can be coupled with other technologies like temperature sensors and GPS tracking modules that can tailor to many different types of applications.

Finally, there are two types of tag styles you can purchase: transponder (like in passive RFID) and beacon.

A transponder tag is similiar to the passive system in terms of the communication protocol. The reader will send a signal to the tag to ask for its code.

A beacon tag will do the opposite and send a signal every so often on its own—but this really cuts down on battery life.

In either passive or active systems, you can have a tag that is read-only or writable. Read-only means just that, you cannot change the tag's data. Writable means that you can choose what data to place within the tag.

Active RFID tags can also get pretty big. Below is one type of form factor; specifically, a ruggedized one:

An active RFID tag. Image courtesy of RFIDinsider.

Communicating with the ID12LA with an Arduino

Phew! Now that we got that out of the way, let’s figure out how to get the ID12LA to communicate with the Arduino.

To follow along, I strongly suggest having the ID12LA's datasheet (PDF) handy.

So with our newfound RFID knowledge, we know that a tag will send a code to the reader, but then what happens? Well, if we study the datasheet, page 4 gives us information on the data output:

This means that once a tag is read, information can be sent out of the reader in serial format, at 9600 baud, No Parity Bit, and 1 Stop Bit. This is a pretty common asynchronous serial communication setup and will make connecting to the Arduino a snap.

Once the reader sends out the data to the Arduino, we need a way to know when to start capturing data. Looking at how the reader spits out data, we find that it uses a Start of Text controller character. Basically, when the serial buffer has some data in it, we can first look to see if this control character is in the queue. If so, then we can go ahead and record the next. If not, we will keep reading until we see it or until the serial buffer is empty.

Assuming we read in the Start of Text controller character, we can go and blindly read in the next 10 ASCII characters from the serial buffer. Then, for the next 5 ASCII characters (2 for checksum, 1 for carriage return, 1 for line feed, and 1 for End of Text controller character), we will read them in but not save it anywhere in our program.

However, to ensure that our transmission was correct, we will double check to see that the End of Text controller character is seen. Though it may rarely be the case, the transmission might fail and we should throw everything we did out the window for the sake of system integrity.

Once the tag is read and saved somewhere in our program, we can use this data for whatever we want! A typical application is access control. You take your saved tag and compare it to a database of tags that are considered to be valid (in our case, we only use one saved tag). The problem is, how do we know what the tag’s code is before we save it to a database? It is not like the tag comes with a paper with its code scribbled on it from the manufacturer.

To work around this and begin to make a database for ourselves, we will need to read in the code and spit it out to the serial monitor. In the Arduino code section, I will provide easy-to-follow comments on where this occurs. When this happens, we will need to write this code down and then alter our program to store this code upon compilation. This is rather a manual way of doing it but this is for the sake of learning the basics of RFID.

Once that is achieved, I would encourage experimenting with programming a simple program sequence that could save RFID tag to EEPROM while the code is running, as well as a way to save and validate more than one tag.

Okay, so let us summarize what the Arduino code must do:

  1. Monitor the serial buffer for available data.
  2. When data is present, read and save it with some validation ensuring communication integrity.
  3. Spit out the data to a serial monitor (primarily for initial setup) and compare this tag to our saved tags.
  4. Perform an action (we will spit out a message to the serial terminal to illustrate this).

Wire it Up

If we turn to page 3 on the datasheet, we see the pinouts to what is essentially a giant IC:

The ID12LA has some nice features such as an output (pin 6) that indicates when a tag is in range and a beeper output (pin 10). However, we don’t use these features in our baseline interface.

For our application, we are using ASCII output. For this to happen, the datasheet tells us (on page 6) that we need to set the format selector input (pin 7) to ground. The data pin we will use is D0 (pin 9). For controlling the reader’s status, we will connect RES (pin 2) to +5V that way the reader is always on.

Refer to the schematic below for the complete overview:

You can also refer to the ID12LA’s pin descriptions:

 

Click to enlarge.

As for getting the ID12LA onto a breadboard, there's a reason that I suggested buying a breakout board from Sparkfun.com or some other reputable shop. The spacing on the ID12LA is not breadboard-friendly, and, unless you have female-to-male jumpers, will be impossible to connect easily.

For an example on how to wire on a breadboard, please take a look at my wiring setup below:

 

My tip is to try and be as neat as possible as it is easy to get lost while wiring. But whatever you do, please ensure the power and ground pins are where they are supposed to be! Follow the schematic!

The capacitor is not optional—it provides important high-frequency power-supply bypassing for the ID12LA.

Arduino Code

As promised, here is the heavily commented code to guide you through all of the logic. This code shows you how to compare the detected tag to one stored tag. The same general techniques can be used to extend the code to compare the detected tag against a database that includes multiple valid tags. 

If you have any questions, leave me a comment below or run to the forums and someone will be happy to assist you!

If you are still new at Arduino programming, however, I suggest reading up on some basic syntax to help with this code.

/*
================================================================================

    File........... ID12LA RFID Test Code
    Purpose........ To demonstrate how to interface to a ID12LA RFID module
    Author......... Joseph Corleto
    E-mail......... corleto.joseph@gmail.com
    Started........ 06/28/2016
    Finished....... 07/02/2016
    Updated........ --/--/----
 
================================================================================
   Notes
================================================================================
- Please visit www.allaboutcircuits.com to search for complete article!

================================================================================
  Updates
================================================================================
*/

//===============================================================================
//  Header Files
//===============================================================================

//===============================================================================
//  Constants
//===============================================================================
// Here is where we save valid tags. When you see the example video
// of this working, I will first show the invalid tag. Then I will comment this 
// line and uncomment the valid tag. This shows you how to manually set your own
// valid tag. Only difference is you will need to manually type this in. I 
// was able to uncomment because I have done this prior to making the video.

// Bogus tag
char tag1[10] = {'X','X','X','X','X','X','X','X','X','X'};

// Good tag
//char tag1[10] = {'3','6','0','0','6','6','0','0','5','C'};

//===============================================================================
//  Variables
//===============================================================================
char ourTag[10];        // We will use this to hold the interrogated tag's data.
boolean tagDetected;    // We can use this to continue program action if our
                         // reading seems like a real tag was detected.
//===============================================================================
//  Pin Declarations
//===============================================================================
//Inputs:
// Serial1 (pin 19) will be used to grab serial data from buffer which is given
// by the ID12LA

//Outputs:
// Serial (pin 2) will be used to output serial data as user feedback to see
// what is going on

//===============================================================================
//  Initialization
//===============================================================================
void setup() 
{
  // Initialize serial port speed for the serial terminal.
  // We will use Serial1 on our MEGA for RFID data and the Serial for messages
  // to the terminal.
  Serial.begin(9600);
  Serial1.begin(9600);

  // Initialize data flags
  tagDetected = false;
}

//===============================================================================
//  Main
//===============================================================================
void loop() 
{
  // This function call will return the interrogated tag's data in form of a char
  // array. If there was an error in the integrity of the transmission, it will
  // return "0000000000". Of course, this only happens unless there is something
  // in the serial buffer. All the while, we also
  // set a flag if there was data there. This comes into use later on.
  if (Serial1.available() > 0)
  {
    // Give some time for all data to arrive safe and sound into the buffer.
    delay(250);
    
    // The if statement below ensures that the beginning of a tag is seen.
    // Remember that a Start of Text is the decimal value of 2. If we do not
    // see this, all bets are off in even continuing to look further into the
    // buffer. I use peek simply because I don't like touching data until I
    // decide to process it.
    if (Serial1.peek() != 2)
    {
      // Log that we did not have a true tag detected.
      tagDetected = false;
      
      // Flush the buffer to bring it back to an initial, known state.
      flushSerial1Buffer();
    }  
    else
    {
      // Looks like the serial data starts with a valid Start of Text character,
      // let mark that we detected a potential tag.
      tagDetected = true;
     
      // Go and process the tag in the serial1 buffer.
      fetchTagData(ourTag);
      // NOTE: The fetchTagData function actually alters the ourTag array
      // declared earlier before. Nothing is returned because if an array's name
      // pass along into a function, it is actually passing by reference, not by
      // value. That means we are changing the array's contents in the function
      // so nothing needs to be returned! There are other spots in this program
      // where this happens so please keep this in mind.
      
      // While we're at it, why not print out the tag's ID.
      Serial.print("Your tag says it is: ");
      Serial.flush();
      printTag(ourTag);
    }
  }
  else
  {
    // We don't flush the buffer here since we know the buffer is zero.
    tagDetected = false;
  }
  
  // If no tag was detected, then the below code will never execute. But, if
  // there is a tag, then we will see if it belongs to our database.
  if (tagDetected)
  {
    // Now here is the part where we do the database comparison with our handy
    // isValidTag function. And this where you may perform an action
    // if it is or is not valid.
    if (isValidTag(ourTag))
    {
      Serial.println("Come on in and have some freshly baked cookies!!!\n");
      Serial.flush();
    }
    else
    {
      Serial.println("No idea who you are but I have released the hounds!!!\n");
      Serial.flush();
    }
  }
}

//===============================================================================
//  Functions
//===============================================================================
////////////////////////
// flushSerial1Buffer //
////////////////////////
void flushSerial1Buffer() 
{  
  // Now there is a function on the Arduino that is called Serial1.flush
  // but it does not really flush the incoming buffer in recent versions, please
  // check arduino.cc for more information on why. So instead, we will just
  // keep on plucking data off of the serial buffer until it is empty!
  while (Serial1.available() > 0)
  {
    Serial.read();
  }
}

//////////////////
// fetchTagData //
////////////////// 
void fetchTagData(char tempTag[]) 
{  
  // First, pluck off the Start of Text character
  Serial1.read();
  
  // Second, read off the tag's actual ID data
  for (int counter = 0; counter < 10; counter++)
  {
    tempTag[counter] = Serial1.read();
  }
 
  // Third, pluck off two checksum, one CR, and one LF characters
  Serial1.read();
  Serial1.read();
  Serial1.read();
  Serial1.read();
  
  // Fourth, pluck off what should be the End of Text character. And
  // while we are plucking, why not throw in a sanity check (mentioned in
  // the article)
  if (Serial1.read() != 3)
  {
    // If for some odd reason the transmission was faulty and we only read
    // in partial information, just throw in dummy data for the tag
    for (int counter = 0; counter < 10; counter++)
    {
      tempTag[counter] = '0';
    } 
  }  
  else
  {
    // But if it all looks good, flush the buffer and keep the previously
    // acquired data
    flushSerial1Buffer();
  }
}

////////////////
// isValidTag //
////////////////
boolean isValidTag(char tempTag[]) 
{  
  boolean result;

  // Compare all of the tags by OR-ing all of the compared tag results. If at
  // least one matches, then it is a valid tag.
  result = compareTags(tempTag, tag1);
      
  return result;
}

/////////////////
// compareTags //
/////////////////
boolean compareTags(char tagA[], char tagB[])
{
  boolean result = true;
  // Basically, we will just compare each character in corresponding array
  // cells until we hit something that does not match. But if it does all
  // match, then our initial state of result will be true.
  for (int counter = 0; counter < 10; counter++)
  {
    if (tagA[counter] != tagB[counter])
    {
      result = false;
      break;
    }
  }
  
  return result;
}

/////////////////
// printTag //
/////////////////
void printTag(char tag[])
{
  // This function just helps identify what the tag ID is so that you
  // may initially read this in, hard code into your program, compile,
  // and then run to have a valid tag in your database.
  for (int counter = 0; counter < 10; counter++)
  {
    Serial.print(tag[counter]);
  }
  Serial.println("");
}


If you've followed all of these steps successfully, you should have your own working passive RFID system. Here's mine in action:

RFID Applications

RFID with access control is a pretty natural and straightforward application— but with some imagination, you can tailor it to different ideas.

For example, if you are familiar with Geocaching, you can hide RFID tags that can open to give clues to other treasures. Or maybe try something like what pet owners do and use an RFID to track your dog.

If you want to go even further, I highly encourage trying out active RFID to broaden the horizon. One application that sticks in my head is someone tagging all of their food and creating a database that gives recipes on what to make for dinner depending on what tags were in the fridge; overkill, but definitely cool! 

 

Give this project a try for yourself! Get the BOM.

ID12LA_RFID_Test_Code_(2).zip

7 Comments
  • W
    Warren Winters July 21, 2016

    I think a really useful opportunity has been missed here.

    This would have been an ideal opportunity to code a ‘State Machine’, and see how useful that form of coding can be to a Real-Time task.

    But, as the code stands, it doesn’t demonstrate much, and I’m quite disappointed.

    Personally, I found that Comment Lines made reading the Code harder.  Take a look at this segment:

    https://gist.github.com/anonymous/301c8ccb12d92cddfa11d8d93e784937

    This is what I chose to do:
    -  Line up the Closing “}” of the If & Else, so that they stick out (On the Arduino IDE, matching Braces get highlighted, and this helps to ensure the Logic is complete)
    -  Put the “//” into Columns 1 & 2, so that they don’t get in the way of the Eye reading the words
    -  Use the “//” comment text in line with the Code, so that you read it to know what the next segment of code is about to do
    -  The next 2 “//” comments are on the same line as the code they are talking about (To me, this is an Assembler thing, which is what I was taught with.  Let’s not try to fool ourselves into thinking that this is a High Level Language, so it’s not really Assembler-style coding - This code is talking to a Machine, not handling a Business problem, which is why - IMHO - a State Machine style of coding would have been superior)
    -  Then, there is a slab of Text, so use the /* ... */ technique - With Indentation - to avoid unnecessary Characters for the eye to process (Again, the Arduino IDE will put this Block of Comments in a different colour to the Code, and the “//” Comments - Another way to help the Comprehension of the whole code)
    -  Let’s not forget the whole Indentation method.  By lining up all the code, then the brain can understand what is related, and what is different, or related in a different manner.
    -  Lastly, the If uses Negative Logic:
          if (Serial1.peek() != 2)
      I was taught never to use Negative Logic, but to instead write
          if (Serial1.peek() == 2)
      This way, the brain can understand more easily, and so you can avoid Double Negatives.


    This is just my 2 cents worth, and there are probably an infinite number of different styles that could be used here - Mine is just one.  All I’m saying is let’s try to be the best we can be, and have the code reflect that.

    OK, now everyone can comment on my comments.

    Like. Reply
    • J
      Joseph Corleto July 22, 2016
      Hello! Thank you for commenting on my article. This is good stuff and this type of response benefits everyone who reads this. Here are my comments: 1) For the braces on "if then else" statements, it was just my personal preference. I have seen braces used a bunch of other ways (including what you showed on github) and I see the appeal to it. But I never really favored them myself. 2) I thought I did line up all of my code segments with proper indentation? 3) Ah yes, comments. Most code I have seen never has any and it really makes me sad. But my commenting style is a bit different when I code programs for myself, I am actually not so verbose with it. It actually looks quite similar to yours! Well, minus the braces convention. But whenever I write an article for others to see, I actually try to be descriptive as possible. I try to link it to the article in some ways. For myself, I usually write comments on the same line, just like you would see in assembly language and just like in your code. 4) Single line comments vs multi line comments. I think you are right, I should use multi line comments to substitute my many single line comments. This was more of something I felt seems clearer either way but I can understand all of those "//" characters getting a bit obtrusive. For future code articles, I will start making more use of multi line comments. Thank you for pointing this out. 5) Negative logic! Almost reminds me of conversations I had in school on whether a is voltage positive or negative, and of course, it depends how you reference it. I think it applies here as well. I was taught to write logic in a way that it made sense in English. To me, using != 2 meant "when this is not a two" or "I don't see a two but I did expect one" or if in a loop "when it is still not two", just made sense. I think this more on how someone thinks about a problem rather a correct way of doing it. Or maybe it is my English : ) 6) I am sorry you did not find my code to demonstrate much. This article was more to help someone with no idea on what RFID is or had little idea what it is. After I got the basics in, I wanted to take a pretty simple RFID module and interface it in a way that was understandable to the masses. For example, many people may not know what a State Machine is and for them to get through my code, I would need to explain that as well or they would need to find this information elsewhere. But I did write in a way to assume that some basic coding skills (particularly with the Arduino) is already present. I have actually not coded in a state machine since college and that was with the Motorola 68000 uP in assembler. It is a great tool. If you think that there is a lot of merit in transforming this code into a state machine after someone has read this implementation, please post this example code in the forum. I would actually like to help out in the process as well if you are willing to take this offer up. I am sure many people (including myself) can benefit from this. Just let me know! Thank you again for your comments!
      Like. Reply
      • Heath Raftery July 22, 2016
        I'm a zealous stickler for readable code and rarely find code that doesn't make me barf. I didn't have a problem at all with this code. Well commented, easy to follow, no unnecessary fluff (really doesn't warrant a state machine) and meets the specification neatly. Style is personal, consistency and comprehensibility is not.
        Like. Reply