Newbie question on looping / if..else / variables

I built a basic sketch using 3 pins - 2 out, 1 in. Both outputs are on PWM pins and I'm using a Pro Mini. The configuration is:

D7 = pushbutton input (PB)
D9 = LED 1
D10 = LED 2

Sketch outline:
PB 1 - Turn on LED 1
PB 2 - Turn on LED 2
PB 3 - Fade LED 2 in and out
PB 4 - Fade LED 1 and 2 in opposite directions
PB 5 - Turn off all LEDs and reset the button count to restart through the sequence

My issue is - I'm polling the pushbutton and so to accept the PB4 (and 5), I have to make sure it is pushed and held through a complete 'fade' cycle. I wanted to modify the sketch to put the fading into the loop to pick up the button press quicker. I added 2 variables... varFade as an increment counter (1-255 back and forth) and varDir to determine whether I am going up or down.

As you can see from the code - I've put in some 'Serial.println' debugging in and I can see I enter the loop, the varFade value enters as 0 which I think it should do from the global variable setup. It successfully calls my function EyeFade and passes the value of varFade. It successfully increments varFade by 5... but then varFade gets reset back to the initial value.

What am I missing here?

Here is my code... I know there is a better way to insert code - I apologize for not knowing that method.

Arden

int BGLEDPin = 9;   //Background LED driver circuit pin 9
int EyeLEDPin = 10;  //Eye LED assigned to pin 8
int BtnPin = 7;     //Button assigned to pin 7
int BtnState = 13;  //Onboard LED
int varBtnPress;    //Will be used to capture button state
int varBtnCnt = 0;  //Button press counter (initialized to 0)
int EyeDelay;       //A variable to establish the speed of eye fade
int varBtnChng = 0; //variable to store the switch change state to 'pressed'
int varDir = 1;
int varFade = 100;

void setup() {
 // Set up serial port
    Serial.begin(9600);   // for troubleshooting
 
 // Set up pins
 pinMode(BGLEDPin,OUTPUT);   //Assigned pin for background set to output mode
 digitalWrite(BGLEDPin,LOW); //Make sure it is off
 pinMode(EyeLEDPin, OUTPUT); //Assigned pin for eye set to output
 digitalWrite(EyeLEDPin,LOW);//Make sure it is off
 pinMode(BtnPin,INPUT_PULLUP); //Assigned pin for button set to input
 pinMode(BtnState,OUTPUT);  //Onboard LED
 } 

void loop() {
 // put your main code here, to run repeatedly:

 //Read the button state
 varBtnPress = BtnPress(); // call the button pressed function; return is 0 if pressed      
 if (varBtnPress == 0)     // this means the button was pressed
   {
     varBtnChng = 1;       // set the 'change' variable to 1 (button state changed)
   }

 if (varBtnPress == 1  && varBtnChng == 1)   // if the button is not pressed but we had a button changed state once
   {   
     varBtnChng = 0;                         // reset the change capture variable to 0
     varBtnCnt = ++varBtnCnt;                // increment the button count
   }
  switch (varBtnCnt)
    {
     case 1:     // First button push
       BGOn ();    // Call the routine to turn on the background LEDs
       break;      // Exit this 'switch' routine
     case 2:     // Second button push
       EyeOn ();   // Call the routine to turn the eye LED on
       break;      // Exit this 'switch' routine
// THIS IS THE LOOP I AM HAVING TROUBLE WITH
     case 3:     // Third button push
       if (varDir == 1)
       {
         Serial.println("top of case 3");
         Serial.println(varFade);          
         EyeFade (varFade);
         varFade = varFade + 5; //varFade increments here, but it always goes back to the default value
         Serial.println(varFade);
         if (varFade == 255)
         {
           varDir = 0;
         }  
       else
       {
         int EyeFade (varFade);
         varFade = varFade - 5;
         if (varFade == 0)
         {
           varDir = 1;  
         }
       }
       }
// END OF THE LOOP I AM HAVING TROUBLE WITH

       break;      // Exit this 'switch' routine
     case 4:      // Fourth button push
       EyeBGFade ();
       break;
     case 5:     // Fifth and final button push
       digitalWrite(BGLEDPin,LOW);   // turn off the eye LED
       digitalWrite(EyeLEDPin,LOW);  // turn off the background LEDs
       varBtnCnt = 0;                // reset the button count
    }
 
}

// Functions all defined here

/* Function Name: BtnPress
* Return variable: varBtnPress
* Return value: 0 = button pressed
* This routine does simple switch read and debounce by using a 10 mS delay
*/

int BtnPress() {
 int varResult,varBtnTest1,varBtnTest2 ; // local variables
 varBtnTest1 = digitalRead(BtnPin);      // read the switch once
 delay (10);                             // delay 10 mS to debounce
 varBtnTest2 = digitalRead(BtnPin);      // read the switch again
 if (varBtnTest1 == varBtnTest2)         // make sure we got 2 consistant readings!
   {
   if (varBtnTest1 == 0)                 // if the button is pressed...
     {
     return varBtnTest1;                 // return the button value (0)
     } 
 else                                    // else...
   {
     return 1;                           // return a 1 (button not pressed)
   }

   }
}

/* Function Name: BGOn
* Return variable: none
* Return value: none
* This routine turns on the background LEDs
*/
int BGOn() {
 digitalWrite(BGLEDPin, HIGH);
//  Serial.println("BGOn function");    // for troubleshooting
}

/* Function Name: EyeOn
* Return variable: none
* Return value: none
* This routine turns on the eye LED
*/
int EyeOn() {
 digitalWrite(EyeLEDPin, HIGH);
//  Serial.println("EyeOn function");   // for troubleshooting
}

void EyeFade(int fadeValue) {
 Serial.print("fadeValue=");
 Serial.println(fadeValue);
 analogWrite(EyeLEDPin,fadeValue);
}


/* Function Name: EyeBGFade
* Return variable: none
* Return value: none
* This routine causes the eye to bright and dim
*/
void EyeBGFade() {
 // fade in from min to max in increments of 5 points:
 for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
   // sets the value (range from 0 to 255):
   analogWrite(EyeLEDPin, fadeValue);
   analogWrite(BGLEDPin, 255-fadeValue);
   // wait for 30 milliseconds to see the dimming effect
   delay(30);
 }
   // fade out from max to min in increments of 5 points:
 for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
   // sets the value (range from 0 to 255):
   analogWrite(EyeLEDPin, fadeValue);
   analogWrite(BGLEDPin, 255-fadeValue);
   // wait for 30 milliseconds to see the dimming effect
   delay(30);  
 }
}
void EyeFade() {
  // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
    analogWrite(EyeLEDPin, fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);

Your problem is that you are waiting here for the fade to run all the way though. This is called blocking code. It blocks execution of other code while it waits for something slow to finish happening. Don't do that. You'll have to rethink your fade routine so that the function only takes one quick step at a time and gets called a lot more often. You also don't want to be using delay for timing.

Code like this:

  for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
//
// <whatever>
//
    delay(30); 
  }

is going to prevent you from doing anything else for over 7.6 seconds. Don't do it. Instead, keep track of where you are in the fade (fadeValue) and how long you have waited using millis() and variables that are declared unsigned long. Use the loop() function for your loops. This link "Using millis() for timing. A beginners guide" from UKHeliBob may help you.

Also, someone with seven posts should know the following:

To post code and/or error messages:

  1. Use CTRL-T in the Arduino IDE to autoformat your complete code.
  2. Paste the complete autoformatted code between code tags (the </> button)
    so that we can easily see and deal with your code.
  3. Paste the complete error message between code tags (the </> button)
    so that we can easily see and deal with your messages.
  4. If you already posted without code tags, you may add the code tags by
    editing your post. Do not change your existing posts in any other way.
    You may make additional posts as needed.
  5. Please provide links to any libraries that are used
    (look for statements in your code that look like #include ). Many libraries
    are named the same but have different contents.

Before posting again, you should read the three locked topics by Nick Gammon near the top of the Programming Questions forum, and any links to which these posts point.

If your project involves wiring, please provide a schematic and/or a wiring diagram and/or a clear photograph of the wiring.

Good Luck!

Thanks to VAJ4088 and DELTA_G.

I have modified my posted code (included the tags - thank you VAJ4088) and also removed the confusing fade code that I had commented out (there is still a fade routine - but when I resolve this first issue, that blocking code will be removed as well).

I am attempting to do what DELTA_G recommended - call my function multiple times instead of dropping into a complete fade loop. The issue is - the value of varFade doesn't seem to 'stick' through the loop - it gets reset to the default value and enters into the case 3 with the preset or default value each time. I am updating the variable varBtnCnt within the loop and it is maintaining the value that it gets set to... so I'm not sure why varFade is not doing the same.

Arden

The keyword you need is "C++ Scope". Variables declared inside functions disappear and are re-created when the function is called again UNLESS they are "static" variables. Global variables don't have that problem.

Try reading this as well:

Demonstration code for doing several things at the same time.

If you post the current code then we may be able to help you further.

When I wrote 7.6 seconds I should have written 1.5 seconds; I missed that the loop variable steps by 5 not 1. However, the points that followed are unchanged.

I think this is basically 'clean' code. The problem I am having ia in the 'case 3' section. I have defined the variable varFade as global (at the top of the sketch) and set it to 0. In 'case 3' in the 'switch' selection group is where I use the variable varFade and either increment or decrement by 5.

My understanding (and it is born out by the results in the serial monitor):
I enter the loop with varFade = 0 and varDir = 1. After 3 button pushes, the first 'if' is encountered in 'case 3'. The value of varFade is still the initial value and is handed off (passed) to function EyeFade as the local variable fadeValue which is then written to the PWM pin with the analogWrite. The function ends, and control is returned to the loop where it left and varFade is now incremented by 5. A quick check is made to see if varFade is now at 255 where if it is (and it currently never is because of the problem I am having), we update varDir to 0 so the next pass through will decrement.

But for some reason - the incremented value of varFade is not maintained but gets reset somewhere and reenters the loop at 0. I figured since I defined varFade as a global variable the scope was wide enough and the local variable in the function EyeFade (fadeValue) is only used within the function, they wouldn't interfere.

So far - I'm only worried about 'case 3' as 'case 4' is still using my blocking code method of fading both LEDs in reverse. Once I figure out where my problem is with this variable, I can apply the same logic to case 4.

Here is my latest (and hopefully cleanest) code:

int BGLEDPin = 9;   //Background LED driver circuit pin 9
int EyeLEDPin = 10;  //Eye LED assigned to pin 8
int BtnPin = 7;     //Button assigned to pin 7
int BtnState = 13;  //Onboard LED
int varBtnPress;    //Will be used to capture button state
int varBtnCnt = 0;  //Button press counter (initialized to 0)
int EyeDelay;       //A variable to establish the speed of eye fade
int varBtnChng = 0; //variable to store the switch change state to 'pressed'
int varDir = 1;
int varFade = 0;

void setup() {
  // Set up serial port
     Serial.begin(9600);   // for troubleshooting
  
  // Set up pins
  pinMode(BGLEDPin,OUTPUT);   //Assigned pin for background set to output mode
  digitalWrite(BGLEDPin,LOW); //Make sure it is off
  pinMode(EyeLEDPin, OUTPUT); //Assigned pin for eye set to output
  digitalWrite(EyeLEDPin,LOW);//Make sure it is off
  pinMode(BtnPin,INPUT_PULLUP); //Assigned pin for button set to input
  pinMode(BtnState,OUTPUT);  //Onboard LED
  } 

void loop() {
  // put your main code here, to run repeatedly:

  //Read the button state
  varBtnPress = BtnPress(); // call the button pressed function; return is 0 if pressed      
  if (varBtnPress == 0)     // this means the button was pressed
    {
      varBtnChng = 1;       // set the 'change' variable to 1 (button state changed)
    }

  if (varBtnPress == 1  && varBtnChng == 1)   // if the button is not pressed but we had a button changed state once
    {   
      varBtnChng = 0;                         // reset the change capture variable to 0
      varBtnCnt = ++varBtnCnt;                // increment the button count
    }
   switch (varBtnCnt)
     {
      case 1:     // First button push
        BGOn ();    // Call the routine to turn on the background LEDs
        break;      // Exit this 'switch' routine
      case 2:     // Second button push
        EyeOn ();   // Call the routine to turn the eye LED on
        break;      // Exit this 'switch' routine
      case 3:     // Third button push
        if (varDir == 1)
        {
          Serial.println("top of case 3");
          Serial.println(varFade);          
          EyeFade (varFade);
          varFade = varFade + 5;
          Serial.println(varFade);
          if (varFade == 255)
          {
            varDir = 0;
          }  
        else
        {
          int EyeFade (varFade);
          varFade = varFade - 5;
          if (varFade == 0)
          {
            varDir = 1;  
          }
        }
        break;      // Exit this 'switch' routine
        }
      case 4:      // Fourth button push
        EyeBGFade ();
        break;
      case 5:     // Fifth and final button push
        digitalWrite(BGLEDPin,LOW);   // turn off the eye LED
        digitalWrite(EyeLEDPin,LOW);  // turn off the background LEDs
        varBtnCnt = 0;                // reset the button count
     }
  
}

// Functions all defined here

/* Function Name: BtnPress
 * Return variable: varBtnPress
 * Return value: 0 = button pressed
 * This routine does simple switch read and debounce by using a 10 mS delay
 */

int BtnPress() {
  int varResult,varBtnTest1,varBtnTest2 ; // local variables
  varBtnTest1 = digitalRead(BtnPin);      // read the switch once
  delay (10);                             // delay 10 mS to debounce
  varBtnTest2 = digitalRead(BtnPin);      // read the switch again
  if (varBtnTest1 == varBtnTest2)         // make sure we got 2 consistant readings!
    {
    if (varBtnTest1 == 0)                 // if the button is pressed...
      {
      return varBtnTest1;                 // return the button value (0)
      } 
  else                                    // else...
    {
      return 1;                           // return a 1 (button not pressed)
    }

    }
}

/* Function Name: BGOn
 * Return variable: none
 * Return value: none
 * This routine turns on the background LEDs
 */
int BGOn() {
  digitalWrite(BGLEDPin, HIGH);
//  Serial.println("BGOn function");    // for troubleshooting
}

/* Function Name: EyeOn
 * Return variable: none
 * Return value: none
 * This routine turns on the eye LED
 */
int EyeOn() {
  digitalWrite(EyeLEDPin, HIGH);
//  Serial.println("EyeOn function");   // for troubleshooting
}

void EyeFade(int fadeValue) {
  Serial.print("fadeValue=");
  Serial.println(fadeValue);
  analogWrite(EyeLEDPin,fadeValue);
}


/* Function Name: EyeBGFade
 * Return variable: none
 * Return value: none
 * This routine causes the eye to bright and dim
 */
void EyeBGFade() {
  // fade in from min to max in increments of 5 points:
  for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 5) {
    // sets the value (range from 0 to 255):
    analogWrite(EyeLEDPin, fadeValue);
    analogWrite(BGLEDPin, 255-fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);
  }
    // fade out from max to min in increments of 5 points:
  for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 5) {
    // sets the value (range from 0 to 255):
    analogWrite(EyeLEDPin, fadeValue);
    analogWrite(BGLEDPin, 255-fadeValue);
    // wait for 30 milliseconds to see the dimming effect
    delay(30);  
  }
}

I don't know if this is the problem but it cannot be correct or clean:

int EyeFade (varFade);

This too is dangerous:

varBtnCnt = ++varBtnCnt;                // increment the button count

The result is undefined. Because of the way that the gcc compiler works, the result may be no change in varBtnCnt.

varBtnCnt = ++varBtnCnt;                // increment the button count

Oh that's a bad one. In the current version of the compiler I believe it does leave the variable unchanged.

vaj4088:
I don't know if this is the problem but it cannot be correct or clean:

int EyeFade (varFade);

Whatever this does, it’s certainly not what OP thinks.

Here’s my wild guess (based on very limited C++ knowledge): it creates a variable (object) of ‘int’ class, named EyeFade, by calling the constructor and assigns it a value of 'varFade'.