user19667: As noted in earlier posts, I am building a model railroad crossing gate signal, complete with gate arms, flashers and sound. Although I haven't settled on exactly how I am going to implement detection of the train entering the zone, determining when its completely passed the entry sensor, tripped the exit sensor and completely passed the exit sensor to re-open the gate, I am researching using RFID for this now.
My thought is to have an RFID card in every car of all my rolling stock. Therefore, I want to read all the ID's of the cars as they go buy and for this particular need, always store the latest ID in a variable so that once the whole train has passed by, the last ID in the variable SHOULD be the ID of the last car in the train. I would also have a counter incrementing for each unique ID read so I can use that as a secondary check for the exit routine (check that the exit RFID reader gets the same car count as the entry reader). The exit reader would also match its exitTag to the entryTag from the entry reader.
I am implementing a state machine to control all this functionality but the problem lies in the RFID reading, I need a way to determine when the reader has read all the train cars tags. I thought the easiest way to do this was to use the elapsedMillis library and monitor for some interval where no card was read (two seconds? that would be way more than the time between two train cars) and once met, change state. 
That is proving more problematic than I thought. Here is my latest attempt.
I also think it might be better if the tag reading method only returned the last tag ID AFTER ITS DETERMINED NO MORE TAGS TO BE READ so that the code in the case statement is not the code that's running continuously.
Note: I am using the Adafruit RFID shield and Mifare Classic 1k S50 IC 13.56MHz RFID cards.
Any thoughts appreciated
case CrossingZoneState::CROSSINGZONE_RFIDDETECTED:
    if (crossingZoneEntered == true)
    {
        // only thing we do here is monitor and identify the RFID tags of each car to determine last cars tag id
       //well, this doesnt work
        if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
        {
            //do all the tag reading in here    
            tag = IndentifyTag(entryRFIDReader);
            readCount += 1;

            if (tag != priorTag)
            {
                tagCount += 1;
            }
            priorTag = tag;
            timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
        }
        // need to figure out how to determine no more cards are being read and change state and crossingZoneEntered back to false
    }

    if (crossingZoneExited == true)
    {

    }
    break;

IdentifyTags method:
uint32_t IndentifyTag(Adafruit_PN532 rfidReader)
{
    uint8_t tagID[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
    uint8_t tagIDLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
    uint32_t rfidCardID = tagID[0];
    boolean success = rfidReader.readPassiveTargetID(PN532_MIFARE_ISO14443A, &tagID[0], &tagIDLength);
    if (success) {
        // Display some basic information about the card for testing
        Serial.println("Found an ISO14443A card");
        Serial.print("  UID Length: "); Serial.print(tagIDLength, DEC); Serial.println(" bytes");
        Serial.print("  UID Value: "); rfidReader.PrintHex(tagID, tagIDLength);

        if (tagIDLength == 4)
        {
            // Mifare Classic card 
            rfidCardID <<= 8;
            rfidCardID |= tagID[1];
            rfidCardID <<= 8;
            rfidCardID |= tagID[2];
            rfidCardID <<= 8;
            rfidCardID |= tagID[3];
            Serial.print("Mifare Classic card #");
            Serial.println(rfidCardID);
        }
        Serial.println("");
    }
    return rfidCardID;
}

Full switch statement:
switch (state)
{
case CrossingZoneState::CROSSINGZONE_CLEAR:
    // only thing we do here is monitor the zone entry sensor
    if (digitalRead(entrySensorPin) == HIGH) {
        crossingZoneEntered = true;
        state = CrossingZoneState::CROSSINGZONE_ACTIVATEGATES;
    }
    break;
case CrossingZoneState::CROSSINGZONE_ACTIVATEGATES:
    // Do these once: turn on the flashers, put down the arms and turn on the crossing gate bells
    if (didOnce = false)
    {
        // turn on flashers
        // turn on sound
        // lower gate arms
        didOnce = true;
        state = CrossingZoneState::CROSSINGZONE_READENTRYRFID;
    }
    break;
case CrossingZoneState::CROSSINGZONE_READENTRYRFID:

    // only thing we do here is monitor and identify the rfid tags of each car to determine last cars tag id
    // need to figure out how to determine no more cards are being read and change state 
        if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
        {
            //do all the tag reading in here    
            entryTag = IndentifyTag(entryRFIDReader);
            readCount += 1;

            if (entryTag != priorTag)
            {
                entryTagCount += 1;
            }
            priorTag = entryTag;
            timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
        }
        else {
            //change state now that entry rfid tag reader is finished
            state = CrossingZoneState::CROSSINGZONE_OCCUPIED;
        }

    break;
case CrossingZoneState::CROSSINGZONE_OCCUPIED:
    // only thing we do here is monitor the zone exit sensor
    if (digitalRead(exitSensorPin) == HIGH) {           
        state = CrossingZoneState::CROSSINGZONE_READEXITRFID;
    }
    break;
case CrossingZoneState::CROSSINGZONE_READEXITRFID:
    if (timeElapsedBetweenCardReads <= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
    {
        //do all the tag reading in here    
        exitTag = IndentifyTag(entryRFIDReader);
        readCount += 1;

        if (exitTag != priorTag)
        {
            exitTagCount += 1;
        }
        priorTag = exitTag;
        timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
    }
    else {//check tags and count now that entry rfid tag reader is finished
        if (entryTagCount == exitTagCount && entryTag == exitTag)
        {
            state = CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES;
        }
    }
    break;
case CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES:
    // Do these once: turn off the flashers, raise the arms and turn off the crossing gate bells
    if (didOnce = true)
    {
        // turn off flashers
        // turn off sound
        // raise gate arms
        didOnce = false;
    }
    break;
case CrossingZoneState::CROSSINGZONE_ERROR:
    boolean success = writeToFileOnSD(modelRRErrorLogFile, "ModelRRXingErrorLog.txt", "error string");
    break;
}


user23966: Here is a solution I found on one of the forums, I modified/simplified it to suit, but it does what you are after.
I use a cheap MP3 player and small amp that runs all the time with the speaker output switched by a baby relay controlled by the UNO R3 and IR sensors from Ebay, you should be able to convert this for use on your player.
It runs the 4 steps you described.
code attached.
(could not figure out how to get code into a box-very confusing..please enlighten me,,,,and what is a back tick??)
#include <Servo.h>

Servo gate1servo;// create servo object to control crossing gate 1
//ASSUMPTION Gate is down at position gatedownposition and up at position gateuppostion  
Servo gate2servo; // create servo object to control crossing gate 2
unsigned long previousMillisSERVOSTART=0; //FLASH Millis() setup
int intervalSERVOSTART = 1000;
unsigned long previousMillisFLASH=0;  //FLASH Millis() setup
int intervalFLASH = 250;
int gateup  =  120;  // servo position for gate up
int gatedown = 30;
int gatepos; // variable to store the servo gateposition
int gp = 120;  // servo position for gate down
int sensor1 = 5; // IR sensor pin Assumption== Pin goes LOW when train detected
int sensor2 = 6; // IR sensor pin Assumption== Pin goes LOW when train detected
int led1 = 10;  // Led 1 pin first alternating flasher
int led2 = 11;  // Led 2 pin first alternating flasher
int gates_started = 0; // this says if the crossing is active

int entering_sensor = 5; //this will tell which sensor was triggered first
int leaving_sensor = 6; // this will tell which sensor shows train leaving
int flash_state = 0;

void setup() {
   Serial.begin(9600);
  gate1servo.attach(3);// attaches the servo on pin 3 to the servo object
  gate2servo.attach(4);// attaches the servo on pin 4 to the servo object
  gate1servo.write(gp);//start assuming no train
  gate2servo.write(gp);//start assuming no train
  pinMode(sensor1, INPUT);  
  pinMode(sensor2, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);  
  digitalWrite(led1, LOW);// Start with all flashers off
  digitalWrite(led2, LOW);
}

void loop() {
    if ((digitalRead (sensor1)==LOW)&& (gates_started==0)) {//read sensor 1, if LOW ...do it
        gates_started = 1;
        leaving_sensor = sensor2;
    }
    if ((digitalRead (sensor2)==LOW)&& (gates_started==0)) {//read sensor 2, if LOW ...do it
        gates_started = 1;                      
        leaving_sensor = sensor1;
    }
    unsigned long currentMillisFLASH = millis();                                                      // get current time stamp, only need one for all if-statements
    if ((unsigned long)(currentMillisFLASH - previousMillisFLASH) >= intervalFLASH) {// time between button presses
       flash_state = ~flash_state;
       digitalWrite(led1, flash_state);                                           //toggle flash_state
      digitalWrite(led2, ~flash_state);
      previousMillisFLASH = currentMillisFLASH;
  }

  unsigned long currentMillisSERVOSTART = millis();                                                     // get current time stamp, only need one for all if-statements
  if ((unsigned long)(currentMillisSERVOSTART - previousMillisSERVOSTART) >= intervalSERVOSTART) {      // time between button presses     
    for(gp = gatedown ; gp <= gateup ; gp++) {                                                          // goes from gatedown  degrees to gateup degrees      
      gate1servo.write(gp);                                                                             // tell servo to go to gateposition in variable 'gateposition'
      gate2servo.write(gp);

  previousMillisSERVOSTART = currentMillisSERVOSTART;
 }
 Serial.println(gp);
}
}


19667: <p>As noted in earlier posts, I am building a model railroad crossing gate signal, complete with gate arms, flashers and sound. Although I haven't settled on exactly how I am going to implement detection of the train entering the zone, determining when its completely passed the entry sensor, tripped the exit sensor and completely passed the exit sensor to re-open the gate, I am researching using RFID for this now.</p>

<p>My thought is to have an RFID card in every car of all my rolling stock. Therefore, I want to read all the ID's of the cars as they go buy and for this particular need, always store the latest ID in a variable so that once the whole train has passed by, the last ID in the variable SHOULD be the ID of the last car in the train. I would also have a counter incrementing for each unique ID read so I can use that as a secondary check for the exit routine (check that the exit RFID reader gets the same car count as the entry reader). The exit reader would also match its exitTag to the entryTag from the entry reader.</p>

<p>I am implementing a state machine to control all this functionality but the problem lies in the RFID reading, I need a way to determine when the reader has read all the train cars tags. I thought the easiest way to do this was to use the elapsedMillis library and monitor for some interval where no card was read (two seconds? that would be way more than the time between two train cars) and once met, change state. </p>

<p>That is proving more problematic than I thought. Here is my latest attempt.
I also think it might be better if the tag reading method only returned the last tag ID AFTER ITS DETERMINED NO MORE TAGS TO BE READ so that the code in the case statement is not the code that's running continuously.</p>

<p><strong>Note: I am using the <a href="https://www.adafruit.com/products/789?gclid=CjwKEAjw3qu5BRC-0uCw8O6Y5zcSJAA_WtdLfmp0bTa24pF0luhnG0aUBFS01u_KlBpT2bMUmcMNzBoCl0Pw_wcB" rel="nofollow">Adafruit RFID shield</a> and <a href="http://www.ebay.com/itm/400985225679?_trksid=p2057872.m2749.l2649&amp;ssPageName=STRK%3AMEBIDX%3AIT" rel="nofollow">Mifare Classic 1k S50 IC 13.56MHz RFID</a> cards.</strong></p>

<p>Any thoughts appreciated</p>

<pre><code>case CrossingZoneState::CROSSINGZONE_RFIDDETECTED:
    if (crossingZoneEntered == true)
    {
        // only thing we do here is monitor and identify the RFID tags of each car to determine last cars tag id
       //well, this doesnt work
        if (timeElapsedBetweenCardReads &lt;= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
        {
            //do all the tag reading in here    
            tag = IndentifyTag(entryRFIDReader);
            readCount += 1;

            if (tag != priorTag)
            {
                tagCount += 1;
            }
            priorTag = tag;
            timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
        }
        // need to figure out how to determine no more cards are being read and change state and crossingZoneEntered back to false
    }

    if (crossingZoneExited == true)
    {

    }
    break;
</code></pre>

<p>IdentifyTags method:</p>

<pre><code>uint32_t IndentifyTag(Adafruit_PN532 rfidReader)
{
    uint8_t tagID[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
    uint8_t tagIDLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
    uint32_t rfidCardID = tagID[0];
    boolean success = rfidReader.readPassiveTargetID(PN532_MIFARE_ISO14443A, &amp;tagID[0], &amp;tagIDLength);
    if (success) {
        // Display some basic information about the card for testing
        Serial.println("Found an ISO14443A card");
        Serial.print("  UID Length: "); Serial.print(tagIDLength, DEC); Serial.println(" bytes");
        Serial.print("  UID Value: "); rfidReader.PrintHex(tagID, tagIDLength);

        if (tagIDLength == 4)
        {
            // Mifare Classic card 
            rfidCardID &lt;&lt;= 8;
            rfidCardID |= tagID[1];
            rfidCardID &lt;&lt;= 8;
            rfidCardID |= tagID[2];
            rfidCardID &lt;&lt;= 8;
            rfidCardID |= tagID[3];
            Serial.print("Mifare Classic card #");
            Serial.println(rfidCardID);
        }
        Serial.println("");
    }
    return rfidCardID;
}
</code></pre>

<p>Full switch statement:</p>

<pre><code>switch (state)
{
case CrossingZoneState::CROSSINGZONE_CLEAR:
    // only thing we do here is monitor the zone entry sensor
    if (digitalRead(entrySensorPin) == HIGH) {
        crossingZoneEntered = true;
        state = CrossingZoneState::CROSSINGZONE_ACTIVATEGATES;
    }
    break;
case CrossingZoneState::CROSSINGZONE_ACTIVATEGATES:
    // Do these once: turn on the flashers, put down the arms and turn on the crossing gate bells
    if (didOnce = false)
    {
        // turn on flashers
        // turn on sound
        // lower gate arms
        didOnce = true;
        state = CrossingZoneState::CROSSINGZONE_READENTRYRFID;
    }
    break;
case CrossingZoneState::CROSSINGZONE_READENTRYRFID:

    // only thing we do here is monitor and identify the rfid tags of each car to determine last cars tag id
    // need to figure out how to determine no more cards are being read and change state 
        if (timeElapsedBetweenCardReads &lt;= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
        {
            //do all the tag reading in here    
            entryTag = IndentifyTag(entryRFIDReader);
            readCount += 1;

            if (entryTag != priorTag)
            {
                entryTagCount += 1;
            }
            priorTag = entryTag;
            timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
        }
        else {
            //change state now that entry rfid tag reader is finished
            state = CrossingZoneState::CROSSINGZONE_OCCUPIED;
        }

    break;
case CrossingZoneState::CROSSINGZONE_OCCUPIED:
    // only thing we do here is monitor the zone exit sensor
    if (digitalRead(exitSensorPin) == HIGH) {           
        state = CrossingZoneState::CROSSINGZONE_READEXITRFID;
    }
    break;
case CrossingZoneState::CROSSINGZONE_READEXITRFID:
    if (timeElapsedBetweenCardReads &lt;= readerInactiveInterval) //only read cards that are continuous, once interval is surpassed change state
    {
        //do all the tag reading in here    
        exitTag = IndentifyTag(entryRFIDReader);
        readCount += 1;

        if (exitTag != priorTag)
        {
            exitTagCount += 1;
        }
        priorTag = exitTag;
        timeElapsedBetweenCardReads = 0;   // reset the counter to 0 so the counting starts over...
    }
    else {//check tags and count now that entry rfid tag reader is finished
        if (entryTagCount == exitTagCount &amp;&amp; entryTag == exitTag)
        {
            state = CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES;
        }
    }
    break;
case CrossingZoneState::CROSSINGZONE_DEACTIVATEGATES:
    // Do these once: turn off the flashers, raise the arms and turn off the crossing gate bells
    if (didOnce = true)
    {
        // turn off flashers
        // turn off sound
        // raise gate arms
        didOnce = false;
    }
    break;
case CrossingZoneState::CROSSINGZONE_ERROR:
    boolean success = writeToFileOnSD(modelRRErrorLogFile, "ModelRRXingErrorLog.txt", "error string");
    break;
}
</code></pre>
 23966: <p>Here is a solution I found on one of the forums, I modified/simplified it to suit, but it does what you are after.</p>

<p>I use a cheap MP3 player and small amp that runs all the time with the speaker output switched by a baby relay controlled by the UNO R3 and IR sensors from Ebay, you should be able to convert this for use on your player.</p>

<p>It runs the 4 steps you described.</p>

<p>code attached.
(could not figure out how to get code into a box-very confusing..please enlighten me,,,,and what is a back tick??)</p>

<pre><code>#include &lt;Servo.h&gt;

Servo gate1servo;// create servo object to control crossing gate 1
//ASSUMPTION Gate is down at position gatedownposition and up at position gateuppostion  
Servo gate2servo; // create servo object to control crossing gate 2
unsigned long previousMillisSERVOSTART=0; //FLASH Millis() setup
int intervalSERVOSTART = 1000;
unsigned long previousMillisFLASH=0;  //FLASH Millis() setup
int intervalFLASH = 250;
int gateup  =  120;  // servo position for gate up
int gatedown = 30;
int gatepos; // variable to store the servo gateposition
int gp = 120;  // servo position for gate down
int sensor1 = 5; // IR sensor pin Assumption== Pin goes LOW when train detected
int sensor2 = 6; // IR sensor pin Assumption== Pin goes LOW when train detected
int led1 = 10;  // Led 1 pin first alternating flasher
int led2 = 11;  // Led 2 pin first alternating flasher
int gates_started = 0; // this says if the crossing is active

int entering_sensor = 5; //this will tell which sensor was triggered first
int leaving_sensor = 6; // this will tell which sensor shows train leaving
int flash_state = 0;

void setup() {
   Serial.begin(9600);
  gate1servo.attach(3);// attaches the servo on pin 3 to the servo object
  gate2servo.attach(4);// attaches the servo on pin 4 to the servo object
  gate1servo.write(gp);//start assuming no train
  gate2servo.write(gp);//start assuming no train
  pinMode(sensor1, INPUT);  
  pinMode(sensor2, INPUT);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);  
  digitalWrite(led1, LOW);// Start with all flashers off
  digitalWrite(led2, LOW);
}

void loop() {
    if ((digitalRead (sensor1)==LOW)&amp;&amp; (gates_started==0)) {//read sensor 1, if LOW ...do it
        gates_started = 1;
        leaving_sensor = sensor2;
    }
    if ((digitalRead (sensor2)==LOW)&amp;&amp; (gates_started==0)) {//read sensor 2, if LOW ...do it
        gates_started = 1;                      
        leaving_sensor = sensor1;
    }
    unsigned long currentMillisFLASH = millis();                                                      // get current time stamp, only need one for all if-statements
    if ((unsigned long)(currentMillisFLASH - previousMillisFLASH) &gt;= intervalFLASH) {// time between button presses
       flash_state = ~flash_state;
       digitalWrite(led1, flash_state);                                           //toggle flash_state
      digitalWrite(led2, ~flash_state);
      previousMillisFLASH = currentMillisFLASH;
  }

  unsigned long currentMillisSERVOSTART = millis();                                                     // get current time stamp, only need one for all if-statements
  if ((unsigned long)(currentMillisSERVOSTART - previousMillisSERVOSTART) &gt;= intervalSERVOSTART) {      // time between button presses     
    for(gp = gatedown ; gp &lt;= gateup ; gp++) {                                                          // goes from gatedown  degrees to gateup degrees      
      gate1servo.write(gp);                                                                             // tell servo to go to gateposition in variable 'gateposition'
      gate2servo.write(gp);

  previousMillisSERVOSTART = currentMillisSERVOSTART;
 }
 Serial.println(gp);
}
}
</code></pre>
