Hey there,
my first post here but i have gathered a lot of help thorugh these forums - so thank you all!
I could not find a thread with my particular question.
In my current project i want to read out several RFID Tags after another to open a relay. The correct sequence of the tags is important. So for example: relay is only triggered, when first Tag #1, then Tag #2 and then tag #3 is read. One wrong tag resets the whole loop to zero.
I came up with this but it seems rather buggy... is there an easier, more professional way (there surely is...):
if(rfid.serNum[0] == 247) {counter = 1;}
else if((counter == 1) && (rfid.serNum[0] == 247)) {counter = 1;}
else if((counter == 1) && (rfid.serNum[0] == 7)) {counter = 2;}
else if((counter == 1) && (rfid.serNum[0] == 135)) {counter = 0;}
else if((counter == 2) && (rfid.serNum[0] == 7)) {counter = 2;}
else if((counter == 2) && (rfid.serNum[0] == 247)) {counter = 1;}
else if((counter == 2) && (rfid.serNum[0] == 135)) {counter = 2134;}
else if((counter == 2134) && (rfid.serNum[0] == 135)) {counter = 2134;}
else {counter == 0;}
I did not want to reset the counter if accidentally the same tag is read twice, therefor the extra lines...
You describe a typical state machine task. Your code will be easier to write and understand as a state machine.
Consider first using a timing loop that compares current millis to a variable to see if more than period of time has past then reset the “step counter” variable back to its initial state.
Now to clean up your loop,
Make an array in setup so that you assign counter(x) with each respective RFID code.
In your loop
IF counter(x) == digital read RFID
Then
Increment x
Set time check to current millis
End IF
IF x > your array definition
then
X=0
Run your unlock code
Else
Loop
That’s pretty much all the logic you need, by creating the an array containing the codes makes it very easy to loop though without having to add tons and tons.
It also gives you the ability to change the array while the program is running so that you could easily make a “learn mode” ect..
@Slumpert: It's not so simple, the TO posted code is better than what you suggest.
Your right, I missed the scope of this was not several but just three cards.
It's not a restricted number of IDs, it's the number of cases which must be considered with every state.
Classic state machine. You need to write a function that reads a tag and a function that compares the tag ID to the specified value.
int State = 0;
void loop()
{
switch (state)
{
case 0: // Ready for first tag
ReadATag();
if (TheTagIs(FirstTag))
State = 1; // Got the first one right
// else stay in State 0
break;
case 1: // Ready for second tag
ReadATag();
if (TheTagIs(SecondTag))
State = 2; // Got the first and second tags right
else
State = 0; // Wrong tag. Go back to looking for the first one
break;
case 2: // Ready for third tag
ReadATag();
if (TheTagIs(ThirdTag))
{
OpenTheLock();
State = 0; // Lock is open. Look for the first one again?
}
else
State = 0; // Wrong tag. Go back to looking for the first one
break;
}
}
One problem: when the ID stays the same, the state should not change, or some similar "debounce" feature.
DrDiettrich:
One problem: when the ID stays the same, the state should not change, or some similar "debounce" feature.
That's part of the beauty of a state machine model. Easy to change the logic. I also switched to an 'enum' for states. That gives the states names instead of numbers and makes it easier to insert states as desired. I also changed the ReadATag() function so it doesn't have to wait for a tag to be read. It returns false if no tag was read. That way loop() can do other stuff while waiting for the next tag.
enum {ReadyForFirstTag, ReadyForSecondTag, ReadyForThirdTag} State = ReadyForFirstTag;
const byte TAG_LENGTH = 10;
char FirstTag[TAG_LENGTH] = {};
char SecondTag[TAG_LENGTH] = {};
char ThirdTag[TAG_LENGTH] = {};
boolean ReadATag()
{
return false; // No tag present
}
boolean TheTagIs(char *ATag)
{
return true;
}
void OpenTheLock() {};
void setup()
{
}
void loop()
{
switch (State)
{
case ReadyForFirstTag: // Ready for first tag
if (ReadATag())
{
if (TheTagIs(FirstTag))
State = ReadyForSecondTag; // Got the first one right
// else stay in State ReadyForFirstTag
}
break;
case ReadyForSecondTag: // Ready for second tag
if (ReadATag())
{
if (TheTagIs(FirstTag))
{} // ignore repeats
else if (TheTagIs(SecondTag))
State = ReadyForThirdTag; // Got the first and second tags right
else
State = ReadyForFirstTag; // Wrong tag. Go back to looking for the first one
}
break;
case ReadyForThirdTag: // Ready for third tag
if (ReadATag())
{
if (TheTagIs(SecondTag))
{} // ignore repeats
else if (TheTagIs(ThirdTag))
{
OpenTheLock();
State = ReadyForFirstTag; // Lock is open. Look for the first one again?
}
else
State = ReadyForFirstTag; // Wrong tag. Go back to looking for the first one
}
break;
}
}
Move ReadATag() before the state machine, nothing can change if nothing was read yet.
DrDiettrich:
Move ReadATag() before the state machine, nothing can change if nothing was read yet.
Feel free to make that change yourself.