RFID door lock sketch issue

hi,
i am attempting to make an RFID controlled door lock for my home.

hardware:
125khz rdm630 rfid reader
125khz tags (12)
single opto isolated relay
12v door strike

i have created a sketch that reads a tag, compares the reading to an array of strings (my tags) stored in program memory, and if the current read is found there will activate the door strike via the relay signal pin for a few seconds.
my program compiles and runs, unlocks for about 2 valid tag reads then will no longer continue to process tag reads - kind of freezes. the rfid reader is still reading the tags as observed by it's led flashing when i bring a tag near but the door strike no longer unlocks
i have tried to minimize sram usage by storing strings in SRAM when possible and have tried commenting out all Serial calls and recompiling but still have same problem.
i read the tag into a String object which gets converted to a string array via String.toCharArray() for the comparison with the stored tags.
this is probably wasteful of resources but I can't seem to get the program to function correctly when I try and read directly into a char array.
could I please get some advice as to where I am going wrong?
the code is below:

#include <SoftwareSerial.h>
#include <avr/pgmspace.h>

SoftwareSerial RFID(6, 7);
String currentTag; //string objest to store current tag read
//pin to control electric door strike - door lock
const int lockPin=4;
// relay module is switched on when signal wire is LOW
const byte Locked=HIGH;
const byte Unlocked=!Locked;
char c;

//All Valid RFID Tags stored in SRAM
const char tag01[] PROGMEM = "111111111111\0";
const char tag02[] PROGMEM = "222222222222\0";
const char tag03[] PROGMEM = "333333333333\0";
const char tag04[] PROGMEM = "444444444444\0";
const char tag05[] PROGMEM= "555555555555\0";
const char tag06[] PROGMEM= "666666666666\0";
const char tag07[] PROGMEM= "777777777777\0";
const char tag08[] PROGMEM= "888888888888\0";
const char tag09[] PROGMEM= "999999999999\0";
const char tag10[] PROGMEM= "AAAAAAAAAAAA\0";
const char tag11[] PROGMEM= "BBBBBBBBBBBB\0";
const char tag12[] PROGMEM= "CCCCCCCCCCCC\0";

PROGMEM const char *myTagArray[] = {tag01,tag02,tag03,tag04,tag05,tag06,tag07,tag08,tag09,tag10,tag11,tag12};

void setup()
{
digitalWrite(lockPin,Locked);
pinMode(lockPin,OUTPUT);
Serial.begin(9600);
RFID.begin(9600);
Serial.print(F("Tag?\n"));
}

void loop()
{
currentTag = "";
while(RFID.available()>0)
{
while(currentTag.length()<14)
{
c=RFID.read();
currentTag += c;
}
}
if (currentTag.length() == 14)
{
currentTag = currentTag.substring(1,13); // removes first and last char
compareToValidTags();
}
}

void compareToValidTags()
{
char tagBuffer[13];
currentTag.toCharArray(tagBuffer,13);
Serial.print(F("\nTag: "));
Serial.print(currentTag);
currentTag = "";
for (int i = 0; i < 12; i++)
{
if (strcmp_P(tagBuffer, (char*)pgm_read_word(&(myTagArray*))) == 0) // Necessary casts and dereferencing, just copy.*

  • {*
  • Serial.println(F(" Valid. Unlocking."));*
  • digitalWrite(lockPin,Unlocked);*
  • delay(5000); //Unlock for 5 seconds*
  • digitalWrite(lockPin,Locked);*
  • Serial.print(F("ReLocked.\n"));*
  • } *
  • }*
    }
    --------------------------------------------------------------------------------------------------------------------------------
    Thank you in advance for any help you can give.
String currentTag; //string objest to store current tag read

Are you using 1.0.4? If not, don't use this.

How to use this forum

Code tags, please. Notice how half your code is in italics?

Also, best to get char arrays working, don't change change to something else. If you have a problem, post what it is.

Hi I am using 1.0.3
The problem is the door stops unlocking after about two valid tags are read. For those two it works well.
Sorry will use code tags from now on, the same code is here:

#include <SoftwareSerial.h>
#include <avr/pgmspace.h>

SoftwareSerial RFID(6, 7);
String currentTag; //string objest to store current tag read
//pin to control electric door strike - door lock
const int lockPin=4;
// relay module is switched on when signal wire is LOW
const byte Locked=HIGH;
const byte Unlocked=!Locked;
char c;

//All Valid RFID Tags stored in SRAM
const char tag01[] PROGMEM = "111111111111\0";
const char tag02[] PROGMEM = "222222222222\0";
const char tag03[] PROGMEM = "333333333333\0";
const char tag04[] PROGMEM = "444444444444\0";
const char tag05[] PROGMEM= "555555555555\0";
const char tag06[] PROGMEM= "666666666666\0";
const char tag07[] PROGMEM= "777777777777\0";
const char tag08[] PROGMEM= "888888888888\0";
const char tag09[] PROGMEM= "999999999999\0";
const char tag10[] PROGMEM= "AAAAAAAAAAAA\0";
const char tag11[] PROGMEM= "BBBBBBBBBBBB\0";
const char tag12[] PROGMEM= "CCCCCCCCCCCC\0";

PROGMEM const char *myTagArray[] = {tag01,tag02,tag03,tag04,tag05,tag06,tag07,tag08,tag09,tag10,tag11,tag12};

void setup()  
{
  digitalWrite(lockPin,Locked); 
  pinMode(lockPin,OUTPUT);  
  Serial.begin(9600);
  RFID.begin(9600);
  Serial.print(F("Tag?\n"));
}



void loop()
{
  currentTag = "";
  while(RFID.available()>0)
  {
    while(currentTag.length()<14)
    {  
      c=RFID.read(); 
      currentTag += c;
    }
  }
  if (currentTag.length() == 14)
  { 
    currentTag = currentTag.substring(1,13); // removes first and last char
    compareToValidTags();
  }
}

void compareToValidTags()
{
  char tagBuffer[13];
  currentTag.toCharArray(tagBuffer,13);
  Serial.print(F("\nTag: "));
  Serial.print(currentTag);
  currentTag = "";
  for (int i = 0; i < 12; i++)
  {
    if (strcmp_P(tagBuffer, (char*)pgm_read_word(&(myTagArray))) == 0) // Necessary casts and dereferencing, just copy. 
    {
      Serial.println(F(" Valid. Unlocking."));
      digitalWrite(lockPin,Unlocked);
      delay(5000); //Unlock for 5 seconds
      digitalWrite(lockPin,Locked);
      Serial.print(F("ReLocked.\n"));
    }  
  }
}

somebone:
Hi I am using 1.0.3
The problem is the door stops unlocking after about two valid tags are read. For those two it works well.

Please note that in versions of the IDE up to and including 1.0.3, the String library has bugs as discussed here and here.

In particular, the dynamic memory allocation used by the String class may fail and cause random crashes.

I recommend reworking your code to manage without String. Use C-style strings instead (strcpy, strcat, strcmp, etc.), as described here for example.

Alternatively, install the fix described here: Fixing String Crashes

Preferably upgrade your IDE to version 1.0.4 or above at: http://arduino.cc/en/Main/Software

Hi again,

Success!
Upgraded to Arduino 1.0.4. then realised the problem after reading up on the serial receive buffer.
The buffer stores 64 bytes and my code wasn't taking into account extra chars read into the buffer by the RFID reader when the tag is presented to it. (It quickly makes multiple reads of same tag)
Changed the loop to read the extra chars out of the serial receive buffer and it worked.
Thanks for the advice Nick Gammon and PaulS.
Nick Gammon: I am still using a String object to hold tag reads and not a char array as you advised but I am definitely going to learn more about manipulating char arrays
Anyway here's the code if anyone is interested:

//   Arduino RFID Door Lock
//   --------------------
//   by somebone
//   17/03/13
// 
//   Code based on RFID examples by maniacbug, sheepdogguides and otaviousp at:
//   http://maniacbug.wordpress.com/2011/10/09/125khz-rfid-module-rdm630/
//   http://sheepdogguides.com/arduino/art3rfid1.htm
//   http://www.instructables.com/id/Arduino-and-RFID-from-seeedstudio/
//
//   And from advice from Nick Gammon and PaulS on arduino.cc forum
//
//   Hardware Required
//   ----------------
//   1 X Arduino Uno or Duemanilove or equivalent clone
//   1 X RDM630 RFID reader
//   1 X Single 5v Opto Isolated Relay Module
// 12 X 125khz RFID tags
//   1 X 12v Electric Door Strike (Fail Secure/NO)
//   1 X 12v 500mA DC Power Supply

#include <SoftwareSerial.h> 
#include <avr/pgmspace.h>

SoftwareSerial RFID(6, 7); // Digital pin 6 to receive tag read by RFID reader
                                    //  Pin 7 not used.

String currentTag; // currentTag String to store tag read by RFID reader

const int lockPin=4; // Digital Pin 4 to control door strike via relay

const byte Locked=HIGH;  //Relay activated when signal input is LOW
const byte Unlocked=!Locked;

// 12 valid RFID tags each of 12 chars in 13 char array terminated by null char stored in flash memory 
const char tag01[] PROGMEM = "000000000001\0";
const char tag02[] PROGMEM = "000000000002\0";
const char tag03[] PROGMEM = "000000000003\0";
const char tag04[] PROGMEM = "000000000004\0";
const char tag05[] PROGMEM = "000000000005\0";
const char tag06[] PROGMEM = "000000000006\0";
const char tag07[] PROGMEM = "000000000007\0";
const char tag08[] PROGMEM = "000000000008\0";
const char tag09[] PROGMEM = "000000000009\0";
const char tag10[] PROGMEM = "000000000010\0";
const char tag11[] PROGMEM = "000000000011\0";
const char tag12[] PROGMEM = "000000000012\0";

// Replace "??????????01\0" etc with 12 chars of each valid RFID tag - must include null char

// To obtain 12 char for any 125khz tags upload code to arduino and scan tags individually
// Tag numbers will be displayed in serial monitor to cut and paste into code
// for uploading again.
// Can use less or more than 12 tags but adjust code to suit 

// Array of pointers to valid tags also stored in flash memory  
PROGMEM const char *validTags[] = {tag01,tag02,tag03,tag04,tag05,tag06,tag07,tag08,tag09,tag10,tag11,tag12};

char c; // To temporarily store a char 

void setup()  
{
  digitalWrite(lockPin,Locked); // Initialise door lock pin
  pinMode(lockPin,OUTPUT);
  Serial.begin(9600); 
  RFID.begin(9600);
  Serial.print(F("Tag?\n")); // Ask for a tag to read
}



void loop()
{
  currentTag = ""; // Clear contents of currentTag String
  while(RFID.available()>0) // While chars left in serial input buffer
  {
    for( int j=0; j<14; j++) // Store the first 14 chars read by reader in currentTag String and remove them from serial input buffer one at a time
    {  
      c=RFID.read(); 
      currentTag += c;
    }
    c=RFID.read(); // Serial input buffer holds 64 bytes (chars). To aviod problems from mulitple reads of same tag in serial input buffer remove rest of chars one by one and discard
  }
  if (currentTag.length() == 14) // If the numbers chars in currentTag string equals 14 (one complete tag) then
  {                                     
    currentTag=currentTag.substring(1,13); // Discard first char and last char as we only need middle 12 chars
    compareToValidTags(); // Compare currentTag to all valid tags and unlock door if valid
  }
}

void compareToValidTags()
{
  char tagBuffer[13]; // Used to convert currentTag String to tagBuffer char array string
  Serial.print(F("\nTag: ")); //## Print currentTag String first
  Serial.println(currentTag); //##
  currentTag.toCharArray(tagBuffer,13); // Copy currentTag String into tagBuffer char array string
  currentTag = ""; // Clear contents of currentTag String
  for (int i = 0; i < 12; i++) // Iterate through each of the 12 valid tags
  {
    if (strcmp_P(tagBuffer, (char*)pgm_read_word(&(validTags))) == 0) 
    // Compare tagBuffer to a valid tag and if equal then unlock door for 10 secs
    {
      Serial.print(F(" Valid. Unlocking for 10 secs.\n")); //##
      digitalWrite(lockPin,Unlocked);
      delay(10000);
      digitalWrite(lockPin,Locked);
      Serial.print(F("ReLocked.\n")); //## Lock up again
    }  
  }
}