RFID (ID-20) gives random characters when used to wake up from sleep.

Hi,

Im running an ID-20 on pin 2 with a 220Ohm resistor to Pin 3 and using the code below for an interupt to bring the arduino out of sleep. I have to scan the tag twice for it to register - the first time there are random characters as described above. How can I fix this issue?

Thanks
John

// Old Question
Hi,
i've been trying to get my RFID module (the ID-20) to wake my arduino from sleep when a card is scanned.

Basically I want my arduino to sleep, and once a card is scanned, it should perform a few actions before going back to sleep.
I have tried using the basic sleep sketch, but the arduino just stays awake - as if the RFID reader is constantly sending data or something?

Thanks for the help
John

Post your code please, and how you have wired it up.

#include <avr/sleep.h>

/* Sleep Demo Serial
 * -----------------
 * Example code to demonstrate the sleep functions in an Arduino.
 *
 * use a resistor between RX and pin2. By default RX is pulled up to 5V
 * therefore, we can use a sequence of Serial data forcing RX to 0, what
 * will make pin2 go LOW activating INT0 external interrupt, bringing
 * the MCU back to life
 *
 * there is also a time counter that will put the MCU to sleep after 10 secs
 *
 * NOTE: when coming back from POWER-DOWN mode, it takes a bit
 *       until the system is functional at 100%!! (typically <1sec)
 *
 * Copyright (C) 2006 MacSimski 2006-12-30 
 * Copyright (C) 2007 D. Cuartielles 2007-07-08 - Mexico DF
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

int wakePin = 2;                 // pin used for waking up
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  // execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  // we don't really need to execute any special functions here, since we
  // just want the thing to wake up
}

void setup()
{
  pinMode(wakePin, INPUT);

  Serial.begin(9600);

  /* Now it is time to enable an interrupt. In the function call 
   * attachInterrupt(A, B, C)
   * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
   * 
   * B   Name of a function you want to execute while in interrupt A.
   *
   * C   Trigger mode of the interrupt pin. can be:
   *             LOW        a low level trigger
   *             CHANGE     a change in level trigger
   *             RISING     a rising edge of a level trigger
   *             FALLING    a falling edge of a level trigger
   *
   * In all but the IDLE sleep modes only LOW can be used.
   */

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
}

void sleepNow()         // here we put the arduino to sleep
{
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     * there is a list of sleep modes which explains which clocks and 
     * wake up sources are available in which sleep mode.
     *
     * In the avr/sleep.h file, the call names of these sleep modes are to be found:
     *
     * The 5 different modes are:
     *     SLEEP_MODE_IDLE         -the least power savings 
     *     SLEEP_MODE_ADC
     *     SLEEP_MODE_PWR_SAVE
     *     SLEEP_MODE_STANDBY
     *     SLEEP_MODE_PWR_DOWN     -the most power savings
     *
     * For now, we want as much power savings as possible, so we 
     * choose the according 
     * sleep mode: SLEEP_MODE_PWR_DOWN
     * 
     */  
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    /* Now it is time to enable an interrupt. We do it here so an 
     * accidentally pushed interrupt button doesn't interrupt 
     * our running program. if you want to be able to run 
     * interrupt code besides the sleep function, place it in 
     * setup() for example.
     * 
     * In the function call attachInterrupt(A, B, C)
     * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
     * 
     * B   Name of a function you want to execute at interrupt for A.
     *
     * C   Trigger mode of the interrupt pin. can be:
     *             LOW        a low level triggers
     *             CHANGE     a change in level triggers
     *             RISING     a rising edge of a level triggers
     *             FALLING    a falling edge of a level triggers
     *
     * In all but the IDLE sleep modes only LOW can be used.
     */

    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 

    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.

}

void loop()
{
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // waits for a second

  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
    }
  }

  // check if it should go to sleep because of time
  if (count >= 10) {
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
}

I have the RFID module wired to pin 0 with a 220ohm resistor between pin 0 and pin 2.

John

Why do this?

void setup()
{

...

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
}

Your comments already say you don't want interrupts in normal running time. And pin 2 will go low for every bit coming in the serial port.

Can you post what you get on the serial port?

Ive just copied and pasted the basic code for interupts and sleep and was hoping that it would work with my RFID module..

I just get Awake for 1 sec to 10 sec and then 'entering sleep mode' in a loop.

John

So I have made progress - I am able to get the RFID module to wake the arduino up now - but how can I make the following sketch run once its awake?

#include <SoftwareSerial.h>

// Create a software serial object for the connection to the RFID module
SoftwareSerial rfid = SoftwareSerial(2,3);

// Set up outputs for the strike plate and status LEDs.
// If you have built the circuit exactly as described in Practical
// Arduino, use pins D12 and D13:
#define strikePlate 12
#define redPin 9
#define greenPin 8
#define buttonPin 10
// If you are using the Freetronics RFID Lock Shield, use pins D6 / D7:
/* #define strikePlate 6 */
/* #define ledPin 7 */

// Specify how long the strike plate should be held open.
#define unlockSeconds 2

// The tag database consists of two parts. The first part is an array of
// tag values with each tag taking up 5 bytes. The second is a list of
// names with one name for each tag (ie: group of 5 bytes).
char* allowedTags[] = {
  "01000554F0",         // Tag 1
  "0100443DE1",         // Tag 2
  "290093E62B",         // Tag 3
  "4F0023FF95",
};

// Check the number of tags defined
int numberOfTags = sizeof(allowedTags)/sizeof(allowedTags[0]);

int incomingByte = 0;    // To store incoming serial data
int buttonState = 0;

/**
 * Setup
 */
void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(strikePlate, OUTPUT);
  digitalWrite(strikePlate, LOW);

  Serial.begin(38400);   // Serial port for connection to host
  rfid.begin(9600);      // Serial port for connection to RFID module

  Serial.print("Keyless Locking System Starting... ");
  Serial.println("Ready!");
  Serial.println("");
}

/**
 * Loop
 */
void loop() {
  byte i         = 0;
  byte val       = 0;
  byte checksum  = 0;
  byte bytesRead = 0;
  byte tempByte  = 0;
  byte tagBytes[6];    // "Unique" tags are only 5 bytes but we need an extra byte for the checksum
  char tagValue[10];

  

  // Read from the RFID module. Because this connection uses SoftwareSerial
  // there is no equivalent to the Serial.available() function, so at this
  // point the program blocks while waiting for a value from the module
  if((val = rfid.read()) == 2) {        // Check for header
    bytesRead = 0;
    while (bytesRead < 12) {            // Read 10 digit code + 2 digit checksum
      val = rfid.read();

      // Append the first 10 bytes (0 to 9) to the raw tag value
      if (bytesRead < 10)
      {
        tagValue[bytesRead] = val;
      }

      // Check if this is a header or stop byte before the 10 digit reading is complete
      if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {
        break;                          // Stop reading
      }

      // Ascii/Hex conversion:
      if ((val >= '0') && (val <= '9')) {
        val = val - '0';
      }
      else if ((val >= 'A') && (val <= 'F')) {
        val = 10 + val - 'A';
      }

      // Every two hex-digits, add a byte to the code:
      if (bytesRead & 1 == 1) {
        // Make space for this hex-digit by shifting the previous digit 4 bits to the left
        tagBytes[bytesRead >> 1] = (val | (tempByte << 4));

        if (bytesRead >> 1 != 5) {                // If we're at the checksum byte,
          checksum ^= tagBytes[bytesRead >> 1];   // Calculate the checksum... (XOR)
        };
      } else {
        tempByte = val;                           // Store the first hex digit first
      };

      bytesRead++;                                // Ready to read next digit
    }

    // Send the result to the host connected via USB
    if (bytesRead == 12) {                        // 12 digit read is complete
      tagValue[10] = '\0';                        // Null-terminate the string


      // Search the tag database for this particular tag
      int tagId = findTag( tagValue );

      // Only fire the strike plate if this tag was found in the database
      if( tagId > 0 )
      {
        Serial.println("Authorized");

        Serial.print("TAG ID ");
        Serial.println(tagId);
        unlock();                             // Fire the strike plate to open the lock
      } else {
        Serial.println("Unauthorized");
                Serial.print(tagValue);
        digitalWrite(redPin, HIGH);
        delay(100);
        digitalWrite(redPin, LOW);
        delay(80);
        digitalWrite(redPin, HIGH);
        delay(100);
        digitalWrite(redPin, LOW);
      }
      Serial.println();     // Blank separator line in output
    }
    
    bytesRead = 0;
  }
}

/**
 * Fire the relay to activate the strike plate for the configured
 * number of seconds.
 */
void unlock() {
  digitalWrite(greenPin, HIGH);
  digitalWrite(strikePlate, HIGH);
  delay(unlockSeconds * 1000);
  digitalWrite(strikePlate, LOW);
  digitalWrite(greenPin, LOW);
}

/**
 * Search for a specific tag in the database
 */
int findTag( char tagValue[10] ) {
  for (int thisCard = 0; thisCard < numberOfTags; thisCard++) {
    // Check if the tag value matches this row in the tag database
    if(strcmp(tagValue, allowedTags[thisCard]) == 0)
    {
      // The row in the database starts at 0, so add 1 to the result so
      // that the card ID starts from 1 instead (0 represents "no match")
      return(thisCard + 1);
    }
  }
  // If we don't find the tag return a tag ID of 0 to show there was no match
  return(0);
}

This is the code to make it fall asleep and wake up with the RFID:

#include <avr/sleep.h>

int wakePin = 2;                 // pin used for waking up
int sleepStatus = 0;             // variable to store a request for sleep
int count = 0;                   // counter

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  // execute code here after wake-up before returning to the loop() function
  // timers and code using timers (serial.print and more...) will not work here.
  // we don't really need to execute any special functions here, since we
  // just want the thing to wake up
}

void setup()
{
  pinMode(wakePin, INPUT);

  Serial.begin(9600);

  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW 
}

void sleepNow()         // here we put the arduino to sleep
{
    
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    

    attachInterrupt(0,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 

    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.

}

void loop()
{
  // display information about the counter
  Serial.print("Awake for ");
  Serial.print(count);
  Serial.println("sec");
  count++;
  delay(1000);                           // waits for a second

  // compute the serial input
  if (Serial.available()) {
    int val = Serial.read();
    if (val == 'S') {
      Serial.println("Serial: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
    }
    if (val == 'A') {
      Serial.println("Hola Caracola"); // classic dummy message
    }
  }

  // check if it should go to sleep because of time
  if (count >= 10) {
      Serial.println("Timer: Entering Sleep mode");
      delay(100);     // this delay is needed, the sleep 
                      //function will provoke a Serial error otherwise!!
      count = 0;
      sleepNow();     // sleep function called here
  }
}

Basically i just need to integrate the two scrupts so that the first will run when the arduino wakes up...

Thanks
John

So, the Arduino now wakes up when the RFID sends data to the Arduino. With what code running? How is the RFID reader attached?

but how can I make the following sketch run once its awake?

You can't. That software uses pin 2 as one of the software serial pins, where your external interrupt is already coming in. You can't then use that pin for something else.

Can't he just use software serial on a different pin?

Can't he just use software serial on a different pin?

Yes, but I don't want to recommend that until I know what is connected to what.

Also, I intend(ed) to recommend NewSoftSerial, instead.

Thanks for the replies!

I have my RFID module connected to the 22ohm resistor into pin 2. This allows it to wake the arduino up when it gets a card read.
But I dont know how to make it read the value from the card like the RFID script wants.

Basically what I'm asking is how to integrate the two pieces of code, and what to plug where to make the code work?

Thanks
John

Move this to other pins, otherwise you can't use pin 2 for the interrupt:

SoftwareSerial rfid = SoftwareSerial(2,3);

In your RFID sketch, add this to setup (like you had in the other sketch):

pinMode(wakePin, INPUT);
  attachInterrupt(0, wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                      // wakeUpNow when pin 2 gets LOW

Copy the wakeUpNow and sleepNow functions to the sketch.

Put:

      sleepNow();     // sleep function called here

into the loop function (so it sleeps each time around the loop). (Maybe keep the timeout to give you time to get the tag ID in).

Then once you wake, grab the data from the RFID gadget.

so what is the wiring for that? I assume that I connect the 220Ohm resistor between the rfid module and pin 2, and just connect the rfid module to a different pin?

Okay so ive got it half working now:

The tag is registered every second time - ie it takes the first scan to wake the arduino up and then the 2nd scan to scan the tag?

Here is my code:

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

// Create a software serial object for the connection to the RFID module
SoftwareSerial rfid = SoftwareSerial(2,4);

// Set up outputs for the strike plate and status LEDs.
// If you have built the circuit exactly as described in Practical
// Arduino, use pins D12 and D13:
#define strikePlate 12
#define redPin 9
#define greenPin 8
#define buttonPin 10
int wakePin = 3;                 // pin used for waking up
// If you are using the Freetronics RFID Lock Shield, use pins D6 / D7:
/* #define strikePlate 6 */
/* #define ledPin 7 */

// Specify how long the strike plate should be held open.
#define unlockSeconds 2

// The tag database consists of two parts. The first part is an array of
// tag values with each tag taking up 5 bytes. The second is a list of
// names with one name for each tag (ie: group of 5 bytes).
char* allowedTags[] = {
  "01000554F0",         // Tag 1
  "0100443DE1",         // Tag 2
  "290093E62B",         // Tag 3
  "4F0023FF95",
};

// Check the number of tags defined
int numberOfTags = sizeof(allowedTags)/sizeof(allowedTags[0]);

int incomingByte = 0;    // To store incoming serial data
int buttonState = 0;

/**
 * Setup
 */
void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(strikePlate, OUTPUT);
  digitalWrite(strikePlate, LOW);

  Serial.begin(38400);   // Serial port for connection to host
  rfid.begin(9600);      // Serial port for connection to RFID module

  Serial.print("Keyless Locking System Starting... ");
  Serial.println("Ready!");
  Serial.println("");
  
  pinMode(wakePin, INPUT);
  attachInterrupt(1, wakeUpNow, LOW); // use interrupt 1 (pin 3) and run function
                                      // wakeUpNow when pin 2 gets LOW
}
void wakeUpNow()        // here the interrupt is handled after wakeup
{
   
}

void sleepNow()         // here we put the arduino to sleep
{
    /* Now is the time to set the sleep mode. In the Atmega8 datasheet
     * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35
     * there is a list of sleep modes which explains which clocks and 
     * wake up sources are available in which sleep mode.
     *
     * In the avr/sleep.h file, the call names of these sleep modes are to be found:
     *
     * The 5 different modes are:
     *     SLEEP_MODE_IDLE         -the least power savings 
     *     SLEEP_MODE_ADC
     *     SLEEP_MODE_PWR_SAVE
     *     SLEEP_MODE_STANDBY
     *     SLEEP_MODE_PWR_DOWN     -the most power savings
     *
     * For now, we want as much power savings as possible, so we 
     * choose the according 
     * sleep mode: SLEEP_MODE_PWR_DOWN
     * 
     */  
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    /* Now it is time to enable an interrupt. We do it here so an 
     * accidentally pushed interrupt button doesn't interrupt 
     * our running program. if you want to be able to run 
     * interrupt code besides the sleep function, place it in 
     * setup() for example.
     * 
     * In the function call attachInterrupt(A, B, C)
     * A   can be either 0 or 1 for interrupts on pin 2 or 3.   
     * 
     * B   Name of a function you want to execute at interrupt for A.
     *
     * C   Trigger mode of the interrupt pin. can be:
     *             LOW        a low level triggers
     *             CHANGE     a change in level triggers
     *             RISING     a rising edge of a level triggers
     *             FALLING    a falling edge of a level triggers
     *
     * In all but the IDLE sleep modes only LOW can be used.
     */

    attachInterrupt(1,wakeUpNow, LOW); // use interrupt 0 (pin 2) and run function
                                       // wakeUpNow when pin 2 gets LOW 
    Serial.println("Asleep");
    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
                             Serial.println("Awake");
    detachInterrupt(1);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.

}


/**
 * Loop
 */
void loop() {
  sleepNow();     // sleep function called here
   byte i         = 0;
  byte val       = 0;
  byte checksum  = 0;
  byte bytesRead = 0;
  byte tempByte  = 0;
  byte tagBytes[6];    // "Unique" tags are only 5 bytes but we need an extra byte for the checksum
  char tagValue[10];

  
  if((val = rfid.read()) == 2) {        // Check for header
    bytesRead = 0;
    while (bytesRead < 12) {            // Read 10 digit code + 2 digit checksum
      val = rfid.read();

      // Append the first 10 bytes (0 to 9) to the raw tag value
      if (bytesRead < 10)
      {
        tagValue[bytesRead] = val;
      }

      // Check if this is a header or stop byte before the 10 digit reading is complete
      if((val == 0x0D)||(val == 0x0A)||(val == 0x03)||(val == 0x02)) {
        break;                          // Stop reading
      }

      // Ascii/Hex conversion:
      if ((val >= '0') && (val <= '9')) {
        val = val - '0';
      }
      else if ((val >= 'A') && (val <= 'F')) {
        val = 10 + val - 'A';
      }

      // Every two hex-digits, add a byte to the code:
      if (bytesRead & 1 == 1) {
        // Make space for this hex-digit by shifting the previous digit 4 bits to the left
        tagBytes[bytesRead >> 1] = (val | (tempByte << 4));

        if (bytesRead >> 1 != 5) {                // If we're at the checksum byte,
          checksum ^= tagBytes[bytesRead >> 1];   // Calculate the checksum... (XOR)
        };
      } else {
        tempByte = val;                           // Store the first hex digit first
      };

      bytesRead++;                                // Ready to read next digit
    }

    // Send the result to the host connected via USB
    if (bytesRead == 12) {                        // 12 digit read is complete
      tagValue[10] = '\0';                        // Null-terminate the string


      // Search the tag database for this particular tag
      int tagId = findTag( tagValue );

      // Only fire the strike plate if this tag was found in the database
      if( tagId > 0 )
      {
        Serial.println("Authorized");

        Serial.print("TAG ID ");
        Serial.println(tagId);
        unlock();                             // Fire the strike plate to open the lock
      } else {
        Serial.println("Unauthorized");
                Serial.print(tagValue);
        digitalWrite(redPin, HIGH);
        delay(100);
        digitalWrite(redPin, LOW);
        delay(80);
        digitalWrite(redPin, HIGH);
        delay(100);
        digitalWrite(redPin, LOW);
      }
      Serial.println();     // Blank separator line in output
    }
    
    bytesRead = 0;
    
  }
  

  // Read from the RFID module. Because this connection uses SoftwareSerial
  // there is no equivalent to the Serial.available() function, so at this
  // point the program blocks while waiting for a value from the module
  
}

/**
 * Fire the relay to activate the strike plate for the configured
 * number of seconds.
 */
void unlock() {
  digitalWrite(greenPin, HIGH);
  digitalWrite(strikePlate, HIGH);
  delay(unlockSeconds * 1000);
  digitalWrite(strikePlate, LOW);
  digitalWrite(greenPin, LOW);
}

/**
 * Search for a specific tag in the database
 */
int findTag( char tagValue[10] ) {
  for (int thisCard = 0; thisCard < numberOfTags; thisCard++) {
    // Check if the tag value matches this row in the tag database
    if(strcmp(tagValue, allowedTags[thisCard]) == 0)
    {
      // The row in the database starts at 0, so add 1 to the result so
      // that the card ID starts from 1 instead (0 represents "no match")
      return(thisCard + 1);
    }
  }
  // If we don't find the tag return a tag ID of 0 to show there was no match
  return(0);
}

and my serial output is:

Keyless Locking System Starting... Ready!

AsleepC¡Ý…­•5
             AsleepýH(Ý…­•5
                           AsleepC¡Ý…[•5
þ¡Ý…­•5                                 Asleep
       Unauthorized
4F00236BB7
AsleepCaPW­•5
             AsleepC¡Ý…­•5
                          AsleepýH(Ý…­•5
                                        AsleepC¡Ý…­•5
                                                     Authorized
TAG ID 2

Asleep

I dont know about those random characters??

John

Note that i am using pin 3 as the interupt - i have the RFID module going into pin 2 still and have the 220Ohm resistor between pins 2 and 3.

John

I can reproduce that, and I think I can see the problem, but I'm not sure how to fix it.

The problem basically is that the low-going edge (which is the start bit) wakes the processor up. However the serial software/hardware needs to see that edge to recognize it as a start bit, but it was asleep when that happened. So it wakes up a fraction too late. The funny characters are probably it incorrectly treating a 0 bit further on as the start bit, and then assembling a garbage character.

Can you not run the RFID reader from a mains power supply? Then it doesn't need to sleep. That's what I do for mine.

Thanks for the help anyway - maybe someone else on here has a solution to the issue.

The problem is that I'm running the whole thing on solar power and batteries, so the less power it uses, the better! The difference is small though so its not a big issue if its not fixable.

Thanks again
John

I did some power-reduction stuff here:

According to the datasheet the ID-20 has a nominal drain of 65 mA whereas the bare-bones setup described above only uses 19 mA even when awake. So the processor isn't really the big issue.

You could use the techniques described on that page to save power at night (when the solar panels are less active, and hopefully the pets are in bed) by turning off your system (say) between 9 pm and 6 am.

Another approach would be to run the processor at a slower clock speed, I believe that saves quite a bit of power, and for receiving 9600 baud, full speed (16 MHz) probably isn't required.

I think I got it to work at last!

#include <Elapsed.h>
#include <avr/sleep.h>

void setup()
{
  Serial.begin(9600);
}


char cur_id [20] = "";
int len = 0;

int wakePin = 3;                 // pin used for waking up
static Elapsed t1;

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  detachInterrupt(1);   // don't want more interrupts on LOW state of pin     
}

void sleepNow()         // here we put the arduino to sleep
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here
  sleep_enable();  
  attachInterrupt (1,wakeUpNow, LOW);    // pin 3
  sleep_mode();            
  sleep_disable();        
}

void loop()
{
  char inByte;

  // sleep after a second of inactivity
  if (t1.intervalMs () > 1000)
  {
    Serial.println ("Asleep");
    sleepNow();     // sleep function called here
    t1.reset ();
    Serial.println ();
    delay (50);
    Serial.println ("Awake");
  }

  // read incoming data:
  if (Serial.available() > 0) 
  {
    // get incoming byte:
    inByte = Serial.read();

    switch (inByte)
    {
    case 2:     // start of text
      len = 0;
      break;

    case 3:   // end of text
      cur_id [len] = 0;
      Serial.println (cur_id);

      // test valid here
      if (strcmp (cur_id, "420123456789") == 0)
      {
        Serial.println ("Accepted");
      }     
      else
      {
        Serial.println ("Rejected");
      }     
      len = 0;  // finished with this one
      break;

    // linefeed, carriage-return
    case 10:
    case 13:
      break;

    // otherwise add to buffer
    default:
      if (len >= (sizeof (cur_id) - 1))
        break;

      cur_id [len++] = inByte;
      break;

    }  // end of switch

  }  // end of incoming data
}  // end of loop

First, I'm using hardware serial. I think that will be more responsive. If you want to send data somewhere else, use software serial for that, because you don't need it to be as time-critical.

Second, and this is what made it work, the ISR has to disable the interrupt on LOW immediately. Like this:

void wakeUpNow()        // here the interrupt is handled after wakeup
{
  detachInterrupt(1);   // don't want more interrupts on LOW state of pin     
}

Without that, I think that it kept getting interrupts (for a few more lines of code) until you hit detachInterrupt. Whilst a few more lines of code might not seem much, I think that delayed it enough to miss catching the start bit.

The RFID reader is my simplified code. You can put back the more complex code that looks up the valid IDs from a table. At least this demonstrates that you can wake up the Atmega from a serial incoming byte.

Thanks for the help mate.

Unfortunately the project that I was working on was due before you posted that, so I couldnt change it, but a couple of mA difference shouldnt be too much of a problem.

Thanks for the help anyway though :slight_smile:

John