Trying to get single button to start / stop a show - non-blocking

Hello,
I am trying to program a mega arduino to start a light / motor "show" when a hardware debounced button is pressed. If the button is pressed during the show, Id like it to stop the show.

I have been adding to LarryD's 3 things at a time code and I was hoping that a buttonpress would change a local variable to high and enable ticktock(). If it were pressed again, or if the showLength time finished, all would be reset. Unfortunately its not turning out that way after I upload. Can you offer any suggestions? Thanks in advance

// http://forum.arduino.cc/index.php?PHPSESSID=q51bliab35m68fmgp1449i55n5&topic=253320.0
// LarryD 3 things at a time
// currently using RC circuit and Schmitt inverter hardware debounced switch
// http://www.jeremyblum.com/2011/03/07/arduino-tutorial-10-interrupts-and-hardware-debouncing/


const unsigned long TaskAtime  = 500UL; //Runs TaskA every .5 second
const unsigned long TaskBtime  = 1000UL; //Runs TaskB every 1 seconds
const unsigned long TaskCtime  = 2000UL; //Runs TaskC every 2 seconds
const unsigned long TaskDtime  = 1*60*1000UL;  //Runs TaskD every 1 minutes
const unsigned long showLength  = 2*60*1000UL;  //time up when 2 min finished

unsigned long TimeA;                     //Times up, Task A time
unsigned long TimeB;                     //Times up, Task B time
unsigned long TimeC;                     //Times up, Task C time
unsigned long TimeD;                     //Times up, Task D time
unsigned long lastPressTime = 0;         // the last time the output pin was toggled

#define buttonPin  2 
#define ledPin  13
#define RELAY1  41                        
#define RELAY2  42
#define RELAY3  43                        
#define RELAY4  44

// boolean ShowStarted = LOW; error that showStated was not declared in void loop scope
boolean ledState = HIGH;         // the current state of the output pin
boolean buttonState;             // the current reading from the input pin
boolean lastButtonState = LOW;   // the previous reading from the input pin

// etc.

unsigned long microsNow;

//========================================================== 
void setup()
{
  microsNow = micros();   //Initailize 

  TimeA = millis();       //Initailize  
  TimeB = TimeA;          //Initialize
  TimeC = TimeA;          //Initialize
  TimeD = TimeA;          //Initialize
  
  pinMode(RELAY1, OUTPUT); 
  digitalWrite(RELAY1,HIGH);          // Turns Relay Off  
  pinMode(RELAY2, OUTPUT);
  digitalWrite(RELAY2,HIGH);          // Turns Relay Off
  pinMode(RELAY3, OUTPUT);
  digitalWrite(RELAY3,HIGH);          // Turns Relay Off
  pinMode(RELAY4, OUTPUT);
  digitalWrite(RELAY4,HIGH);          // Turns Relay Off
  
  pinMode(buttonPin, INPUT);    // Set the button pin as input
  pinMode(ledPin, OUTPUT);      // Set the status led pin as output
  digitalWrite(ledPin,LOW);          // would this Turns Status LED Off?


} // >>>>>>>>>>>>>> END OF setup() <<<<<<<<<<<<<<<<<


void loop()
{
  //==================
  boolean showStarted;
  int reading = digitalRead(buttonPin); // load hardware debounced button into local variable
  if (reading != lastButtonState) {
    lastPressTime = millis(); // update timer with every button press (is release a problem?)
  
  
  // if show hasnt started and button is pressed start show
    if(reading == LOW && showStarted == LOW && (millis() - lastPressTime) > 2000){
      showStarted = HIGH;
      digitalWrite(ledPin, showStarted); // turn on status LED
    }      
  // if show has started and button is pressed stop show - reset
    if(reading == LOW && (millis() - lastPressTime) < showLength){
      showStarted = LOW;
      digitalWrite(ledPin, showStarted);  // Turn off status LED
      digitalWrite(RELAY1,HIGH);          // Turns Relay Off
      digitalWrite(RELAY2,HIGH);          // Turns Relay Off
      digitalWrite(RELAY3,HIGH);          // Turns Relay Off
      digitalWrite(RELAY4,HIGH);          // Turns Relay Off
    }
    if((millis() - lastPressTime) > showLength){
      showStarted = LOW;
      digitalWrite(ledPin, showStarted);  // Turn off status LED
      digitalWrite(RELAY1,HIGH);          // Turns Relay Off
      digitalWrite(RELAY2,HIGH);          // Turns Relay Off
      digitalWrite(RELAY3,HIGH);          // Turns Relay Off
      digitalWrite(RELAY4,HIGH);          // Turns Relay Off
    }

  
  
  lastButtonState = reading;
  }
  //==================
  //Run time sensitive show tasks if showStarted variable is true
  //Do this every 1000us (i.e. 1ms)
  if (showStarted == LOW && micros() - microsNow >= 1000UL)  
  {                                  
    microsNow = micros();  //Re-initialize for next iteration
    TickTock();            //It is time to check
  }
  //==================


} // >>>>>>>>>>>>>> END OF loop() <<<<<<<<<<<<<<<<<


//========================================================== 
//                  FUNCTIONS
//========================================================== 
//Check to see if time sensitve Tasks should run
void TickTock() 
{
  //1ms has gone by, check if there is a Task to run
  unsigned long millisNow = millis();

  //==================
  if (millisNow - TimeA >= TaskAtime) //Is it time to run Task A?
  {
    TimeA = millis();                 //Re-initialize
    TaskA();
  } 
  //==================
  if (millisNow - TimeB >= TaskBtime) //Is it time to run Task B?
  {
    TimeB = millis();                 //Re-initialize
    TaskB();
  }  
  //==================
  if (millisNow - TimeC >= TaskCtime) //Is it time to run Task C?
  {
    TimeC = millis();                 //Re-initialize
    TaskC();
  }  
  //==================
  if (millisNow - TimeD >= TaskDtime) //Is it time to run Task D?
  {
    TimeD = millis();                 //Re-initialize
    TaskD();
  }  

  //Other time task checking goes here as needed

}

//===Every 0.5 sec =============== 
void TaskA()
{
   digitalWrite(41,!digitalRead(41));   //Toggle pin 41
}

//====Every 1 sec ==============
void TaskB()
{
  digitalWrite(42,!digitalRead(42));   //Toggle pin 42
  //Other stuff

}

//=====Every 2 sec =============
void TaskC()
{
  digitalWrite(43,!digitalRead(43));   //Toggle pin 43
  //Other stuff

}

//=====Every 1 min =============
void TaskD()
{
  digitalWrite(44,!digitalRead(44));   //Toggle pin 44
  //Other stuff

}

//======================================================================
//                             END OF CODE
//======================================================================

// boolean ShowStarted = LOW; error that showStated was not declared in void loop scopeShowStarted !== showStated.

ShowStarted !== showStated

Is that meant to read "ShowStarted != ShowStarted" ?

while the showStarted !== showStarted comment is interesting, Im not sure where or how it is appliled. Plus, the heart of my concern is what is going on in the void loop() routine. I believe in there is where the logic isnt behaving as I had hoped

Unless you plan on holding the button down for the full 2 minutes, you should only be checking for one edge, either falling or rising, not both.

good clue Arrch, thanks. So then I should only be polling for reading to be LOW (since my button pulls low).

But I guess what I'm asking for is a comment for if this is a correct strategy for trying to do what Im doing. The heart of it lies in the loop routine where I'm looking for a button press if the show is not running to start it, and if it is running to stop it and wait for the next button press. The particular section is below:

  // if show hasnt started and button is pressed start show
    if(reading == LOW && showStarted == LOW && (millis() - lastPressTime) > 2000){
      showStarted = HIGH;
      digitalWrite(ledPin, showStarted); // turn on status LED
    }      
  // if show has started and button is pressed stop show - reset
    if(reading == LOW && (millis() - lastPressTime) < showLength){
      showStarted = LOW;
      digitalWrite(ledPin, showStarted);  // Turn off status LED
      digitalWrite(RELAY1,HIGH);          // Turns Relay Off
      digitalWrite(RELAY2,HIGH);          // Turns Relay Off
      digitalWrite(RELAY3,HIGH);          // Turns Relay Off
      digitalWrite(RELAY4,HIGH);          // Turns Relay Off
    }
    if((millis() - lastPressTime) > showLength){
      showStarted = LOW;
      digitalWrite(ledPin, showStarted);  // Turn off status LED
      digitalWrite(RELAY1,HIGH);          // Turns Relay Off
      digitalWrite(RELAY2,HIGH);          // Turns Relay Off
      digitalWrite(RELAY3,HIGH);          // Turns Relay Off
      digitalWrite(RELAY4,HIGH);          // Turns Relay Off
    }

  
  
  lastButtonState = reading;
  }
  //==================
  //Run time sensitive show tasks if showStarted variable is true
  //Do this every 1000us (i.e. 1ms)
  if (showStarted == HIGH && (micros() - microsNow) >= 1000UL)  
  {                                  
    microsNow = micros();  //Re-initialize for next iteration
    TickTock();            //It is time to check
  }
  //==================

I believe it would be much easier to see what is happening if you separate the reading of the button from the decision about starting or stopping. Your code could look a bit like this and there should be no need for a whole nest of complex IF statements.

void loop() {
   readAndSaveButton();
   runShow();
}

void readAndSaveButton() {
    // read button and set a variable called showRun to be either true or false.
}

void runShow() {
   if (showRun == true) {
      // all the stuff that makes your show work
   }
  else {
       // stop stuff happening
  }
}

The demo code in the first post in this Thread may be of interest.

...R

redhotdaddy:
while the showStarted !== showStarted

That is not what I wrote and not what you wrote in your code. Read it carefully.

comment is interesting,

I was pointing out why you got a compiler error. Check your spelling and the case of each of the letters in your variable name.

lemming:

ShowStarted !== showStated

Is that meant to read "ShowStarted != ShowStarted" ?

Nope. It's meant to read exactly as I typed it. It explains why he got a compiler error.

Henry_Best:
// boolean ShowStarted = LOW; error that showStated was not declared in void loop scopeShowStarted !== showStated.

I think your shorthand has confused people who don't see the point you were making.

...R

Oh Henry_Best, you had a typo that was confusing. I think you were trying to say that I had a type case mismatch.
ShowStarted is not the same as showStarted. That is likely the reason why I got that compile error.

Unfortunately you wrote: showStated and not showStarted.

which I think was just a typo between Stated and Started , yes?

The point that I was trying to make was not the variable names (even though I "corrected" their spelling in my example) but rather the ShowStarted!==showStated is an evaluation type statement. As such it should have something like "if(ShowStarted!==showStated)...." wrapped around it.

However, I had assumed that you made the mistake of using "==" instead of "=" for the assertion of the value of one variable to another. Right or wrong, that was the point I was making.

redhotdaddy:
Oh Henry_Best, you had a typo that was confusing. I think you were trying to say that I had a type case mismatch.
ShowStarted is not the same as showStarted. That is likely the reason why I got that compile error.

Unfortunately you wrote: showStated and not showStarted.

I wrote exactly what intended to write.

which I think was just a typo between Stated and Started , yes?

It was your typo, I was merely pointing it out to you. See your original post.// boolean ShowStarted = LOW; error that showStated was not declared in void loop scope

Robin2:

Henry_Best:
// boolean ShowStarted = LOW; error that showStated was not declared in void loop scopeShowStarted !== showStated.

I think your shorthand has confused people who don't see the point you were making.

...R

Not only do they not see the point, they don't see their own errors, even when they're pointed out to them. :0

Always good to cut&paste or Quote a post

lemming:
if(ShowStarted!==showStated)

However, I had assumed that you made the mistake of using "==" instead of "=" for the assertion of the value of one variable to another. Right or wrong, that was the point I was making.

!== for not equal is wrong

!= for not equal is right

Henry_Best:

Robin2:

Henry_Best:
// boolean ShowStarted = LOW; error that showStated was not declared in void loop scopeShowStarted !== showStated.

I think your shorthand has confused people who don't see the point you were making.

...R

Not only do they not see the point, they don't see their own errors, even when they're pointed out to them. :0

Do errors made in comments count except for confusing programmers?

Robin2, that is exactly what I was looking for. Thank you for providing an improved strategy idea.

I was getting hung up on Henry_Best's comment, I now see that he was referring to my typo in the comments about the error. Perhaps he didnt realize that the line was commented out and I put a note there to explain why. Thank you for your detailed review. I was looking for help with the direction of my project, but pointing out a typo in the comments gives so much more.