millis() and Seqencing Code

Not sure if this is the right forum, sorry. I am having some issues with creating a timing circuit that will allow me to compare against time, post a button push and then run code in sequence based on that time.

What my code is supposed to do is:
startPB pressed 1st time, then MP3 trigger plays track #1 (track #1 is 5.3 seconds long)
if startPB pressed 2nd time during first 5.3 seconds, then abort,
if startPB pressed 2nd time after the first 5.3 seconds then do nothing,
after first 5.3 seconds elapses after 1st startPB press go to Gate control,

My problem is that my code works when I press the start PB (the MP3 track #1 plays) but then it jumps to the gate control runs almost immediately. I am having a heck of a time working through a millis() delay cycle.

My questions are:
1 - Can I create a counter that will allow me to compare against a fixed number (5350), if so…how. I am at a loss to make this work.
2 - Do I need to keep my counting circuit in the loop() or can I move it outside of the loop() and still get a proper calculated value?
3 - I am also a bit confused with the millis() since I am unclear if it restarts each time the loop() cycles??

Thanks in advance for your help. Yes, I am new at this.
Mike

// Definition of variables that change

int outPin = 1;			      // communication line to the MP3 Trigger
int startpbVal = 0;                   // variable for reading the Start PB state
int startpbState = 0;                 // variable for holding the start PB state 
int gateupVal = 0;                    // variable for reading the Start PB state
int gateupState = 0;                  // variable for holding the start PB state 
volatile int startpbcount = 0;        // initialize start counter at 0
volatile int gateupcount = 0;         // initialize gate up counter at 0
unsigned long pastTime = 0;            // this is the time that has passed (none as default)
unsigned long startPBtimer = 0;	      // this holds the time from when the startPB was first pushed

// Pin assignments
const int startpbPin = 2;                   // Start pushbutton
const int gateupPin = 3;                    // Initialization/Reset sequence pushbutton
const int grnledPin = 5;                    // Green LED on the light tree
const int yelled2Pin = 6;                   // Yellow #2 LED on the light tree
const int yelled1Pin = 7;                   // Yellow #1 LED on the light tree
const int redledPin = 8;                    // Red LED on the light tree
const int upsolPin = 9;                     // Solenoid that holds the gate up
const int dwsolPin = 10;                    // Solenoid that holds the gate down
//const unsigned long startMP3 = 5350;
long randNumber;                            // sets variable rand "random" to a long integer.

void setup() {    

  Serial.begin(9600);                       //Initialize serial communications
  pinMode(outPin, OUTPUT);                  //transmit info to MP3 Trigger to play specified track
  pinMode(redledPin, OUTPUT);               //Output to Red LED transistor for LED on light tree
  pinMode(yelled1Pin, OUTPUT);              //Output to Yellow1 LED transistor for LED on light tree   
  pinMode(yelled2Pin, OUTPUT);              //Output to Yellow2 LED transistor for LED on light tree
  pinMode(grnledPin, OUTPUT);               //Output to Green LED transistor for LED on light tree
  pinMode(upsolPin, OUTPUT);                //Output to Gate Up Solenoid transistor 
  pinMode(dwsolPin, OUTPUT);                //Output to Gate Down Solenoid transistor
  pinMode(startpbPin, INPUT);               //start and abort pushbutton (abort not functioning yet)
  pinMode(gateupPin, INPUT);                //gate up PB which functions only once for now.
  //startPBtimer = millis();                  //sets the startPBtimer to record milliseconds
  digitalWrite(upsolPin, LOW);              //Part of the command to drive the solenoid down so that the gate doesn't go up out of control
  digitalWrite(dwsolPin, HIGH);             //part of the command to drive the solenoid down so that the gate doesn't go up out of control
}

 void loop() {
  
      gateupVal = digitalRead(gateupPin);          //read input value and store it in gateupVal
   if (gateupVal != gateupState){           	//start button state has changed!
        gateupcount = gateupcount++;              // adds one to the gate up counter
   if (startpbcount == 0){
     if (gateupcount == 1){                     //checks to see if the startPB has been pushed and if the gateUP PB has been pushed 
        gateup();		               //goes to gateup subroutine
    }
   }
  }
   
   startpbVal = digitalRead(startpbPin);      // read input value and store it in startpbVal
   if (startpbVal != startpbState){           // start button state has changed!
	  startpbcount = startpbcount++;}     // add one to the startpbcount
   if (startpbcount == 2){		      // checks for first startPB press 
       start();  			      // goes to start subroutine
     }
   unsigned long timePassed = startPBtimer - pastTime; // math to determine total time passed since PB press
   if (startpbcount == 3){
     if (timePassed >= 5350){		      //checks for first startPB variable = 2 and that the timer is equal or above the required delay to play the MP3 			
        gate();                               // goes to the gate drop subroutine
     }
   }
  if (startpbcount == 4){
     if (timePassed <= 5350){      // checks for second startPB press 
       abort();					// and goes to abort subroutine
      }
   }
  void start(){
//starts the start commands MP3
   Serial.begin(38400); 
   pastTime = startPBtimer;	// this captures when the start PB was first pushed. Used in the abort sequence.
   startPBtimer = millis();     // start time is now back to current time
   Serial.write('t');		//lowercase "t" must be in single quotes…
   Serial.write(1);		//commands MP3 trigger to play track001
   startpbcount = startpbcount++;  // adds one to the start PB counter to allow the "Gate" void to run (from the void loop)
   return;			//return from start routine
}
 }

My questions are: 1 - Can I create a counter that will allow me to compare against a fixed number (5350), if so...how. I am at a loss to make this work. 2 - Do I need to keep my counting circuit in the loop() or can I move it outside of the loop() and still get a proper calculated value? 3 - I am also a bit confused with the millis() since I am unclear if it restarts each time the loop() cycles??

  1. Yes. Just keep in mind that millis() wraps back to zero about every month and a half.
  2. You can move it outside the loop, but you should keep in mind that your timing resolution will depend on how frequently you interrogate it. If you call it once on each execution of loop(), then (generally) you may as well keep the code inside loop().
  3. The millis() value is set to zero when the board is reset and runs continuously so long as interrupts aren't blocked. The loop() function is just an ordinary function that is called repeatedly by the (invisible) main() function. It is present only to help you write cyclic code and, in its simplistic implementation, is completely independent and "unaware" of millis().

if (gateupVal != gateupState){ //start button state has changed!

I prefer variable names that make sense. If the comment is wrong, fix it. Otherwise, it makes more sense if the variable names in this statement are something like:

if(currStartVal != prevStartVal)
{
   // Start switch state has changed

If the comment is wrong, then the code should look like:

if(currGateVal != prevGateVal)
{
   // Gate switch state has changed

If the comments are hard to maintain, get rid of them. Misleading comments are worse than no comments.

Comparing xxxVal and xxxState appears to be comparing apples and oranges.

      gateupVal = digitalRead(gateupPin);          //read input value and store it in gateupVal
   if (gateupVal != gateupState){             //start button state has changed!
        gateupcount = gateupcount++;              // adds one to the gate up counter
   if (startpbcount == 0){
     if (gateupcount == 1){                     //checks to see if the startPB has been pushed and if the gateUP PB has been pushed 
        gateup();                      //goes to gateup subroutine
    }
   }
  }

Putting each { on a new line, and using Tools + Auto Format makes this code look like:

      gateupVal = digitalRead(gateupPin);          //read input value and store it in gateupVal
      if (gateupVal != gateupState)
      {             //start button state has changed!
         gateupcount = gateupcount++;              // adds one to the gate up counter
         if (startpbcount == 0)
         {
            if (gateupcount == 1)
            {                     //checks to see if the startPB has been pushed and if the gateUP PB has been pushed 
                gateup();                      //goes to gateup subroutine
            }
         }
      }

which, in my humble opinion, is a hell of a lot easier to read.

It also makes it easier to see that this:

  void start(){
//starts the start commands MP3
   Serial.begin(38400); 
   pastTime = startPBtimer;    // this captures when the start PB was first pushed. Used in the abort sequence.
   startPBtimer = millis();     // start time is now back to current time
   Serial.write('t');      //lowercase "t" must be in single quotes…
   Serial.write(1);        //commands MP3 trigger to play track001
   startpbcount = startpbcount++;  // adds one to the start PB counter to allow the "Gate" void to run (from the void loop)
   return;         //return from start routine
}

is INSIDE of loop(), where it can NOT be.

Thanks Morris and PaulS. I didn't realize that there was an "auto format" built in the Arduino code. I am not a programmer so I am sure that my code is very primative, but thank you very much for your help. I am still having a bit of an issue that seems to elude me. For the most part I have worked out most of the kinks, but there are three ??? that are plaguing me.

Here is how it starts: 1 - I want to press the "Gate Up" PB to make my gate go up...works flawlessly, but then the start() loop begins automatically (which I don't want). The gate() loop then runs perfectly (if you neglect that the start() started automatically). 2 - The other problem is that when the start() loop begins, I want to be able to press the start PB again and abort in the first 7 sec or so, which works, but it should reset the system back to the "ready" position awaiting a "Start" PB press. 3 - I can't seem the get the timer to work properly and I fear that that may be the issue...

I have near 20 hours of troubleshooting in this (I am not joking) I am just not a programmer and I am really just hacking. I wish I have more time to learn, alas...I don't. Any help would be great.

Thanks guys. Here is the complete code:....in the next post

and now the code that goes with my previous message:

// Definition of variables that change

int outPin = 1;			      // communication line to the MP3 Trigger
int currStartVal = 0;                   // variable for reading the Start PB state
int prevStartVal = 0;                 // variable for holding the start PB state 
int currGateVal = 0;                    // variable for reading the Start PB state
int prevGateVal = 0;                  // variable for holding the start PB state 
volatile int startpbcount = 0;        // initialize start counter at 0
volatile int gateupcount = 0;         // initialize gate up counter at 0
long startPBtime = 0;	              // this holds the time from when the startPB was first pushed

// Pin assignments
const int startpbPin = 2;                   // Start pushbutton
const int gateupPin = 3;                    // Initialization/Reset sequence pushbutton
const int grnledPin = 5;                    // Green LED on the light tree
const int yelled2Pin = 6;                   // Yellow #2 LED on the light tree
const int yelled1Pin = 7;                   // Yellow #1 LED on the light tree
const int redledPin = 8;                    // Red LED on the light tree
const int upsolPin = 9;                     // Solenoid that holds the gate up
const int dwsolPin = 10;                    // Solenoid that holds the gate down
long randNumber;                            // sets variable rand "random" to a long integer.

void setup() {    

  Serial.begin(38400);                       //Initialize serial communications
  pinMode(outPin, OUTPUT);                  //transmit info to MP3 Trigger to play specified track
  pinMode(redledPin, OUTPUT);               //Output to Red LED transistor for LED on light tree
  pinMode(yelled1Pin, OUTPUT);              //Output to Yellow1 LED transistor for LED on light tree   
  pinMode(yelled2Pin, OUTPUT);              //Output to Yellow2 LED transistor for LED on light tree
  pinMode(grnledPin, OUTPUT);               //Output to Green LED transistor for LED on light tree
  pinMode(upsolPin, OUTPUT);                //Output to Gate Up Solenoid transistor 
  pinMode(dwsolPin, OUTPUT);                //Output to Gate Down Solenoid transistor
  pinMode(startpbPin, INPUT);               //start and abort pushbutton (abort not functioning yet)
  pinMode(gateupPin, INPUT);                //gate up PB which functions only once for now.
  digitalWrite(upsolPin, LOW);              //Part of the command to drive the solenoid down so that the gate doesn't go up out of control
  digitalWrite(dwsolPin, HIGH);             //part of the command to drive the solenoid down so that the gate doesn't go up out of control
}

 void loop() {
  
   long sysTime= millis();
   
   currGateVal = digitalRead(gateupPin);
       //read input value and store it in currGateVal
   if (currGateVal != prevGateVal)
   {           	//start button state has changed!
        gateupcount = gateupcount++;            // adds one to the gate up counter
   if (startpbcount == 0)
     {                      // start PB must be exactly 0 to allow 
     if (gateupcount == 1)
       {                     //checks to see if the startPB has been pushed and if the gateUP PB has been pushed 
        gateup();	     //goes to gateup subroutine
       }
     }
    }
   
   currStartVal = digitalRead(startpbPin);
     // read input value and store it in currStartVal
   if (currStartVal != prevStartVal)
     {           // start button state has changed!
	  startpbcount = startpbcount++;
     }     // add one to the startpbcount
   if (startpbcount == 1)
     {		      // checks for first startPB press 
      if (gateupcount == 2)
      {
      startPBtime = sysTime;                  // sets the startPBtime long to the current system time
      start();  			      // goes to start subroutine
      }
     }
  
  if (sysTime - startPBtime >= 7600)
    {      // checks for first startPB variable = 2 and that the timer is equal or above the required delay to play the MP3 			
          if (startpbcount == 3)
       {                    // this is the start of the gate up commands
        gate();                               // goes to the gate drop subroutine
       }
    }
  
  if (sysTime - startPBtime < 7600)
    {       // checks for second startPB press 
    if (startpbcount == 4)
      {
       abort();				      // and goes to abort subroutine
      }
     }
     
   }
   
void gateup(){
  
// commands the gate to go up either at initialization of session or after a drop has been executed.
    //Serial.begin(38400);                        //establishes communications to the MP3 trigger
    Serial.write('t');			        //command to mp3 trigger to initialize
    Serial.write(3);			        //command to mp3 trigger to play track 3
    digitalWrite(grnledPin, HIGH);		//sets the Green LED to on
    delay(2250);				//delay to allow initialization tone to complete
    digitalWrite(upsolPin, HIGH);		//actuate the upward driving solenoid
    digitalWrite(dwsolPin, LOW);		//deactivate the downward driving solenoid
    digitalWrite(grnledPin, LOW);		//signal completion of the initialization sequence
   
 // Reset of the gate PB counter, start PB counter and all associated variables
    gateupcount = 2;                    // sets the gate to a permissive for the start sequence
    currGateVal = 0;                      // variable for reading the Gate Up PB variable reset
    prevGateVal = 0;                    // State for holding the Gate Up PB state reset 
    startpbcount = 1; 
    currStartVal = 0;                     // variable for holding the start PB state  
    prevStartVal = 0;                   // State for holding the start PB state
   return;				// return from gateup routine
}

void start(){
//starts the start commands MP3
   //Serial.begin(38400); 
   Serial.write('t');		//lowercase "t" must be in single quotes…
   Serial.write(1);		//commands MP3 trigger to play track001
   startpbcount = 3;  // adds one to the start PB counter to allow the "Gate" void to run (from the void loop)
   return;			//return from start routine
  }

void gate(){
   //Serial.begin(38400); 
   randNumber = random(100, 2700);	        //Generates a random number between 100 and 2700 (.1 sec to 2.7 sec)
   delay(randNumber);                    	//sets random number into delay for start circuit
   Serial.write('t');                     	//lowercase "t" must be in single quotes…
   Serial.write(2);                      	//causes the MP3 trigger to play track002
   delay(0060);
   digitalWrite(redledPin, HIGH);         	//sets the RED LED to on
   delay(0120);                           	//sets delay for .120 seconds
   digitalWrite(yelled1Pin, HIGH);       	//sets the Yellow LED #1 to on
   delay(0120);                          	//sets delay for .120 seconds
   digitalWrite(yelled2Pin, HIGH);        	//sets the Yellow led #2 to on
   delay(0120);                        		//sets delay for .120 seconds
   digitalWrite(grnledPin, HIGH);      	        //sets the Green LED to on
   digitalWrite(upsolPin, LOW);           	//command to drop the gate
   digitalWrite(dwsolPin, HIGH);		//command to drop the gate 
   delay(2250);				        //rollout delay for tone and lights
   digitalWrite(redledPin, LOW);		//sets Red LED to off
   digitalWrite(yelled1Pin, LOW); 	        //sets Yellow LED #1 to off
   digitalWrite(yelled2Pin, LOW);		//sets Yellow LED #2 to off
   digitalWrite(grnledPin, LOW);		//sets Green LED #1 to off
   startpbcount = 0;			        //resets the startpbcount  counter back to zero so that the sequence can start again.
   currStartVal = 0;                              // variable for holding the start PB state  
   prevStartVal = 0;                            // State for holding the start PB state
   startPBtime = 0;                             // resets the startPBtime back to zero
   gateupcount = 0;
   currGateVal = 0;                               // variable for reading the Gate Up PB variable reset
   prevGateVal = 0;                             // State for holding the Gate Up PB state reset
   return;				        //return from gate drop routine
}

void abort() {
   //Serial.begin(38400); 
   Serial.write('t');                           //command to mp3 trigger to initialize
   Serial.write(4);                             //command to mp3 trigger to play track 4
   digitalWrite(redledPin, HIGH);               //while playing abort tone, hold red light on
   delay(1000);
   startpbcount = 0;			        //resets the startpbcount  counter back to zero so that the sequence can start again.
   currStartVal = 0;                              // variable for holding the start PB state  
   prevStartVal = 0;                            // State for holding the start PB state;
   startPBtime = 0;                             // resets the startPBtime back to zero
   digitalWrite(redledPin, LOW);                //turns the red LED off
   //return;                                   //exit abort routine
}

You have:

    currGateVal = 0;                      // variable for reading the Gate Up PB variable reset
    prevGateVal = 0;                    // State for holding the Gate Up PB state reset 

    currStartVal = 0;                     // variable for holding the start PB state  
    prevStartVal = 0;                   // State for holding the start PB state

in gateup(). The prevXXXVal assignments are wrong and in the wrong place. The currXXXVal assignments are unnecessary.

The prevXXXVal assignments should be:

prevGateVal = currGateVal;
prevStartVal = currStartVal;

and should be in loop().

Do you see a difference between currGateVal and gateupcount? In the first one, it is easy to pick out that the variable is associated with the Gate. In the second one, it is not. In the first one, it is easy to see that the variable represents the value of a pin. In the second one, it is not easy to see that the variable represents a count. getUpCount would correct both of those issues. Look for the (plenty of) other places where camel case names would improve the readability of the code. gateup (vs. digitalRead), for instance.

Paul,

Your insight is proving invaluable. I am wrapping my head around those comments and last night after I posted this, I did a bit of testing on my timer circuits and the math that is is supposed to be executing. Turns out it isn’t and I am trying to figure this out also. I am running an Arduino Uno R2 board and the following code isn’t calculating what I want it to calculate. The code below is part of the larger code above with the additions and changes you (PaulS) have recommended, so all of the variables have been identified.

I have used the “blinkwithoutdelay” sample code (which I think you recommended to me in January) and I can’t seem to get this to work. here is what I want this to do:

1 - press the start PB, capture the current system time (startPBtime)
2 - cycle through specific code if the (sysTime - startPB) is more than or less than a particular number.

what it shows me in some test code that I put together if that the math comes out to 0, but I was expecting a calculated number. confusing to say the least, can you tell me if I am missing something?

Thanks again!
Mike

 void loop() {
  
   long sysTime= millis();
   prevStartVal = currStartVal;
   prevGateVal = currGateVal;
   
   currGateVal = digitalRead(gateupPin);
       //read input value and store it in currGateVal
   if (currGateVal != prevGateVal)
   {           	//start button state has changed!
        gateupcount = gateupcount++;            // adds one to the gate up counter
   if (startpbcount == 0)
     {                      // start PB must be exactly 0 to allow 
     if (gateupcount == 1)
       {                     //checks to see if the startPB has been pushed and if the gateUP PB has been pushed 
        gateup();	     //goes to gateup subroutine
       }
     }
    }
   
   currStartVal = digitalRead(startpbPin);
     // read input value and store it in currStartVal
   if (currStartVal != prevStartVal)
     {           // start button state has changed!
	  startpbcount = startpbcount++;
     }     // add one to the startpbcount
   if (startpbcount == 2)
     {		      // checks for first startPB press 
      if (gateupcount == 2)
      {
      startPBtime = sysTime;                  // sets the startPBtime long to the current system time
      start();  			      // goes to start subroutine
      }
     }
  
  if (sysTime - startPBtime >= 7600)
    {      // checks for first startPB variable = 2 and that the timer is equal or above the required delay to play the MP3 			
          if (startpbcount == 3)
       {                    // this is the start of the gate up commands
        gate();                               // goes to the gate drop subroutine
       }
    }
  
  if (sysTime - startPBtime < 7600)
    {       // checks for second startPB press 
    if (startpbcount == 4)
      {
       abort();				      // and goes to abort subroutine
      }
     }
     
   }

I'd need to see the changes you made to the other functions, to determine what is going wrong. It would be helpful if you used a variable name other than startpbcount for your state name. The name you are using implies that you are counting the number of times the start switch was pressed. If that were the case, the value should not be modified inside gateup().

You can use Serial.print() and Serial.println() statements in setup(), loop(), and the other functions to see what value the state and time variables have at different places, and to see what portions of the code actually are being executed.