0

Help with while loop exit condition
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 1:40 pm

Good afternoon everyone.

I'm trying to make a security system with my son for his bedroom using the adafruit nfc shield to arm and disarm the system.
Everything is working with one exception.
We are using a laser as a tripwire, and when the system is armed I have a while loop running that monitors the analog input from a photoresistor to monitor if the system is tripped. once the input drops below a certain threshold the while loop breaks.

The problem is that I cant figure out how to make the nfc shield monitor for a card to disarm the system when the while loop is running. as is the only way to disarm the system is to trip it first.

Code is as follows:

Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include <Adafruit_PN532.h>

#define IRQ   (2)
#define RESET (3)  // Not connected by default on the NFC Shield

Adafruit_PN532 nfc(IRQ, RESET);

bool alarmState = false;  //initialize variable which represents the state of the alarm.. armed vs disarmed
int alarmLedPin = 13;
int laserPin = 12;
int sensorPin = A3;
int sensorValue = 0;

//////////////////////////////////// SETUP

void setup() {

Serial.begin(9600);  // set up Serial library at 9600 bps
pinMode(alarmLedPin, OUTPUT);
pinMode(laserPin, OUTPUT);
pinMode(sensorPin, INPUT);

nfc.begin();  // find Adafruit RFID/NFC shield

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
 
  // configure board to read RFID tags
  nfc.SAMConfig();

}
/////////////////////////////////// LOOP
void loop() {
 
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
  uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

   // wait for RFID card to show up!
  Serial.println("Waiting for an Access Card ...");
   
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  uint32_t cardidentifier = 0;
 
  if (success) {
    // Found a card!
    Serial.print("Card detected #");
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
   
    if (cardidentifier == 574277710) { // this is the card's unique identifier
        alarmState = !alarmState;  // if it's on turn it off and if its off turn it on     
        digitalWrite(alarmLedPin, LOW);       
          if (alarmState == true){
            Serial.println("System is Armed"); 
            digitalWrite(laserPin, HIGH);
            digitalWrite(alarmLedPin, LOW);
            delay(50);
            sensorValue = analogRead(sensorPin);     
          }
          ////////////this is where i'm having trouble//////////////////
          //// I need the nfc shield to read a card while this loop is executing
          while (alarmState == true){   
            //delay(500); //delay for ease of serial debugging
            if (sensorValue > 600){
              Serial.println(sensorValue); // monitor sensor salue in serial monitor
            }         
            if (sensorValue < 600){  // if the beam is interrupted this is what happens
              Serial.println("Defense Systems Activated!!");
              Serial.println("Use Key Card to Disarm System");
              digitalWrite(alarmLedPin, HIGH);
              digitalWrite(laserPin, LOW);
              break;
            }   
                sensorValue = analogRead(sensorPin);   
            }
            if (alarmState == false){
              Serial.println("System is Disarmed");
              digitalWrite(laserPin, LOW);
            }
            delay(3000);  //delay to remove card
      }     
      if (cardidentifier != 574277710) {
        Serial.println("Access Denied");
        delay(3000);// delay to remove card
      }
  }
}


I would really appreciate any help.

Thanks!!
Last edited by celtic_smith on Mon May 20, 2019 1:49 pm, edited 1 time in total.

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by franklin97355 on Mon May 20, 2019 1:48 pm

You are not checking for alarmstate inside your while loop so it will never exit once inside.

franklin97355
 
Posts: 21229
Joined: Mon Apr 21, 2008 2:33 pm
Location: Lacomb, OR.

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 1:56 pm

Code: Select all | TOGGLE FULL SIZE
          ////////////this is where i'm having trouble//////////////////
          //// I need the nfc shield to read a card while this loop is executing
          while (alarmState == true){   
            //delay(500); //delay for ease of serial debugging
            if (sensorValue > 600){
              Serial.println(sensorValue); // monitor sensor salue in serial monitor
            }         
            if (sensorValue < 600){  // if the beam is interrupted this is what happens
              Serial.println("Defense Systems Activated!!");
              Serial.println("Use Key Card to Disarm System");
              digitalWrite(alarmLedPin, HIGH);
              digitalWrite(laserPin, LOW);
              break;
            }

Part of the problem is that your while loop is only executed when a card has already been detected.

There are two possible approaches. One is to use the optional timeout parameter so that your code won't block forever waiting for a card:
Code: Select all | TOGGLE FULL SIZE
bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength, uint16_t timeout = 0); //timeout 0 means no timeout - will block forever.

Then take turns polling for a card and checking the beam.

A better approach is to connect your sensor to an interrupt pin so even if you are blocked waiting for a card, you can trip the alarm.

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 2:14 pm

Thanks very much for the reply... I understood a bit of it.

Sorry I may be a bit out of my depth with this project. I haven't tried anything like this in a while.

If i understand correct the interrupt pins are 2 and 3... already in use by the shield. can i still use them for something else?

as far as the code goes I'm sorry I don't understand. I'm sure you are right but I don't quite get it. My logic is:

I need to be monitoring continuously once the system is armed. If I can just read a card in the while loop I can add an exit state but I don't know how to do that.

Sorry for the density on my part I really do appreciate the help, it may just be a bit above my understanding.

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 2:41 pm

If i understand correct the interrupt pins are 2 and 3..

That is true if you are using an Arduino UNO. Other Arduino boards have different interrupt pins.

If I can just read a card in the while loop I can add an exit state but I don't know how to do that.

But your while loop is inside the 'if' statement for a detected card. So you won't even get to your loop until a card is read.
Code: Select all | TOGGLE FULL SIZE
  if (success) {
    // Found a card!


If you add a timeout parameter to your call to readPassiveTargetID, it will not block indefinitely.

Then you can make that call from inside your while loop.

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 3:23 pm

lollol i'm using my 10 year old decimilia for this, it's older than the kid i'm trying to help

ok, I think I understand, I modified the code to this:

Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include <Adafruit_PN532.h>

#define IRQ   (2)
#define RESET (3)  // Not connected by default on the NFC Shield

Adafruit_PN532 nfc(IRQ, RESET);

bool alarmState = false;  //initialize variable which represents the state of the alarm.. armed vs disarmed
int alarmLedPin = 13;
int laserPin = 12;
int motorPin = 11;
int sensorPin = A3;
int sensorValue = 0;

//////////////////////////////////// SETUP

void setup() {

Serial.begin(9600);  // set up Serial library at 9600 bps
pinMode(alarmLedPin, OUTPUT);
pinMode(laserPin, OUTPUT);
pinMode(sensorPin, INPUT);
pinMode(motorPin, OUTPUT);

nfc.begin();  // find Adafruit RFID/NFC shield

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
 
  // configure board to read RFID tags
  nfc.SAMConfig();

}
/////////////////////////////////// LOOP
void loop() {
 
  boolean success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
  uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

   // wait for RFID card to show up!
  Serial.println("Waiting for an Access Card ...");
   
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  bool readPassiveTargetID(uint8_t cardbaudrate, uint8_t * uid, uint8_t * uidLength, uint16_t timeout = 10);
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  uint32_t cardidentifier = 0;
 
  if (success) {
    // Found a card!
    Serial.print("Card detected #");
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
   
    if (cardidentifier == 574277710) { // this is the card's unique identifier
        alarmState = !alarmState;  // if it's on turn it off and if its off turn it on     
        digitalWrite(alarmLedPin, LOW);       
          if (alarmState == true){
            Serial.println("System is Armed"); 
            digitalWrite(laserPin, HIGH);
            digitalWrite(alarmLedPin, LOW);
            delay(50);
            sensorValue = analogRead(sensorPin);     
          }
          ////////////this is where i'm having trouble//////////////////
          //// I need the nfc shield to read a card while this loop is executing
          while (alarmState == true){   
            delay(500); //delay for ease of serial debugging
            if (sensorValue > 600){
              Serial.println(sensorValue); // monitor sensor salue in serial monitor
            }         
            if (sensorValue < 600){  // if the beam is interrupted this is what happens
              Serial.println("Defense Systems Activated!!");
              Serial.println("Use Key Card to Disarm System");
              digitalWrite(alarmLedPin, HIGH);
              digitalWrite(laserPin, LOW);
              digitalWrite(motorPin, HIGH);
              delay(2000);
              digitalWrite(motorPin, LOW);   
              break;
            }   
            if (success){
              cardidentifier = uid[3];
              cardidentifier <<= 8; cardidentifier |= uid[2];
              cardidentifier <<= 8; cardidentifier |= uid[1];
              cardidentifier <<= 8; cardidentifier |= uid[0];
              if (cardidentifier == 574277710){
                break;
              }   
            }
            sensorValue = analogRead(sensorPin);       
          }
          if (alarmState == false){
            Serial.println("System is Disarmed");
            digitalWrite(laserPin, LOW);
          }
          delay(3000);  //delay to remove card
      }     
      if (cardidentifier != 574277710) {
        Serial.println("Access Denied");
        delay(3000);// delay to remove card
      }
  }
}


Now the while loop executes once, since success is still true from the initial call?

I'm not sure if I added the timout function correctly.

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 3:52 pm

lollol i'm using my 10 year old decimilia for this, it's older than the kid i'm trying to help

The Diecimila has the same pinout and interrupts as the UNO. So still pins 2 and 3. PIn-change interrupts are available on any pin. But that's more of an advanced topic.

I'm not sure if I added the timout function correctly.

Yes. That will give you a 10 millisecond timeout on checking for the card.

Now the while loop executes once, since success is still true from the initial call?

Which loop? The loop() function or your while loop? It looks like your while loop is still inside the card detect 'if' statement.

If you post a sample of the serial output it should give us an idea of the execution path.

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 4:13 pm

the serial output is as follows

Found chip PN532
Firmware ver. 1.6
Waiting for an Access Card ...
Card detected #574277710 // card is initially seen by reader
System is Armed
922 // values from the sensor
924
921
922
923
924
921
922
922
923
921
923
Defense Systems Activated!! // i block the beam with my finger
Use Key Card to Disarm System
Waiting for an Access Card ...
Card detected #574277710 // the card is put near the reader again
System is Disarmed
Waiting for an Access Card ...

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 4:39 pm

OK. That is consistent with the way the code reads.

If you scan the card one more time, does it re-arm the system?

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 4:40 pm

yes it does

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 4:47 pm

OK. So how would you like it to behave differently?

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 4:54 pm

I need to be able to escape the while loop when the card is placed on the reader. otherwise it just stays in the "armed" state until it's tripped, I would like to me able to "unarm" it once it's armed without having to set it off.

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by adafruit_support_bill on Mon May 20, 2019 5:03 pm

Since you still have your while loop inside the 'if' statement where you read the card, the card never gets read in your loop.

You either need to add another call to readPassiveTargetID (with a short timeout) inside your while loop. Or get rid of the loop altogether and implement a state machine.

adafruit_support_bill
 
Posts: 74687
Joined: Sat Feb 07, 2009 10:11 am

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 5:27 pm

adafruit_support_bill wrote:You either need to add another call to readPassiveTargetID (with a short timeout) inside your while loop.


That sounds like a great idea..... how do I do that.

you, have, btw been super helpful and I really appreciate it, but I really need this drawn in crayon for me.

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Re: Help with while loop exit condition

by celtic_smith on Mon May 20, 2019 5:43 pm

Holy S***t I made it work!

I had to modify the library itself to get the timout to function, but now it works like a charm

The working code as follows:

Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include <Adafruit_PN532.h>

#define IRQ   (2)
#define RESET (3)  // Not connected by default on the NFC Shield

Adafruit_PN532 nfc(IRQ, RESET);

bool alarmState = false;  //initialize variable which represents the state of the alarm.. armed vs disarmed
int alarmLedPin = 13;
int laserPin = 12;
int sensorPin = A3;
int sensorValue = 0;

//////////////////////////////////// SETUP

void setup() {

Serial.begin(9600);  // set up Serial library at 9600 bps
pinMode(alarmLedPin, OUTPUT);
pinMode(laserPin, OUTPUT);
pinMode(sensorPin, INPUT);

nfc.begin();  // find Adafruit RFID/NFC shield

  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
 
  // configure board to read RFID tags
  nfc.SAMConfig();

}
/////////////////////////////////// LOOP
void loop() {

  boolean success;
 
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
  uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  // wait for RFID card to show up!
  Serial.println("Waiting for an Access Card ...");

   
  // Wait for an ISO14443A type cards (Mifare, etc.). When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
 
  uint32_t cardidentifier = 0;
 
  if (success) {
    // Found a card!
    Serial.print("Card detected #");
    // turn the four byte UID of a mifare classic into a single variable #
    cardidentifier = uid[3];
    cardidentifier <<= 8; cardidentifier |= uid[2];
    cardidentifier <<= 8; cardidentifier |= uid[1];
    cardidentifier <<= 8; cardidentifier |= uid[0];
    Serial.println(cardidentifier);
   
    if (cardidentifier == 574277710) { // this is the card's unique identifier
        alarmState = !alarmState;  // if it's on turn it off and if its off turn it on     
        digitalWrite(alarmLedPin, LOW);         
                 
              if (alarmState == true){
              Serial.println("System is Armed"); 
              digitalWrite(laserPin, HIGH);
              digitalWrite(alarmLedPin, LOW);
              delay(1000);
              sensorValue = analogRead(sensorPin);     
             
              while (alarmState == true){
                delay(300);               
                if (sensorValue > 600){
                  Serial.println(sensorValue);
                  digitalWrite(alarmLedPin, LOW);
                }     
               
                if (sensorValue < 600){
                  Serial.println("Defense Systems Activated!!");
                  Serial.println("Use Key Card to Disarm System");
                  digitalWrite(alarmLedPin, HIGH);
                  digitalWrite(laserPin, LOW);
                  break;
                }
                success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
                uint32_t cardidentifier = 0;
                if(success){
                  cardidentifier = uid[3];
                  cardidentifier <<= 8; cardidentifier |= uid[2];
                  cardidentifier <<= 8; cardidentifier |= uid[1];
                  cardidentifier <<= 8; cardidentifier |= uid[0];
                    if (cardidentifier == 574277710) {
                      digitalWrite(laserPin, LOW);
                      break;
                    }
                }
               
                sensorValue = analogRead(sensorPin);     
              }
            }
            if (alarmState == false){
              Serial.println("System is Disarmed");
              digitalWrite(laserPin, LOW);
            }
            delay(3000);  //delay to remove card
    }     
    if (cardidentifier != 574277710) {
      Serial.println("Access Denied");
      delay(3000);// delay to remove card     
    }
  }
}


Thanks I really appreciate all of your help with this!

celtic_smith
 
Posts: 17
Joined: Tue Mar 11, 2008 7:50 pm

Please be positive and constructive with your questions and comments.