Help with using button to change function!?

Hello! :smiley:

Okay, so I'm really getting stuck in to some basic programming with my arduino but there's one thing I just cant seem do do efficiently.
What i want to achieve is to have a single tactile button. When you push it, it starts function 1, again will stop one and start 2, again will start 3 and stop 2, and the final time will stop 3. Basically I need it to be like this:

Imagine below that i have already set up the program and the functions are written out where stated "BLAH". In between the *** *** Is basically what i need to know how to do, but i also need it to be able to do that in the middle of a function; not just at the finish of each function loop.

Void loop()
if(***BUTTON PRESSED ONCE****);
{ Run function 1}
if (***During function 1 Button is pressed***);
{ Run function 2}
if (***During function 2 Button is pressed***);
{Run function 3}
if (***During function 3 Button is pressed***);
{End fuction 3}

void function_1()
{BLAH}

void function_2()
{BLAH}

void function_3()
{BLAH}

Its a mighty big ask, but it may also be a simple answer... One mans weakness is another mans strength!
Cheers, Al

You need some kind of state machine and your functions have to be transformed a bit.

void loop()
{
  static uint8_t nState= 0;
  if(***BUTTON PRESSED****)
    nState++;

  switch(nState)
  {
    case 1:
      function1();
      break;
    case 2:
      function1_stop();
      nState++;
    case 3:
      function2();
      break;
    case 4:
      function2_stop();
      nState++;
    case 5:
      function3();
      break;
    case 6:
      function3_stop();
      nState= 0;
      break;
    case 0:
    default:
  }
}

Your functions should do something small and then exit to be called by the loop() in a few ns again to continue. Split up the work into small pieces and build stop functions for cleanup / leaving of the function.

Please add code tags (# button) in your post.

  if(***BUTTON PRESSED****)
    nState++;

The BUTTON PRESSED part is, obviously, a digitalRead() on the pin that the switch is attached to. But, there is more to it than that.

You want to increment nState only once when the switch is pressed. Doing so requires knowing when a transition occurs - from released to pressed and from pressed to released. That requires storing the state of the switch on each pass through loop, so you can compare the current state to the previous state.

int prevState = HIGH;
int currState;

void loop()
{
   currState = digitalRead(switchPin);
   if(currState != prevState)
   {
      // A transition occurred
      if(currState == LOW)
      {
         // ... to Pressed
         nState++;
      }
   }
   prevState = currState;

   // Use nState...
}

Ahhhh! I see! Its starting to click with me now haha! for now i have only TWO functions/subroutines, and the third can always be added later, but if i paste in the code i have so far could you help me apply your solutions into it? Still a tad confused - I'm a noob to programming let alone arduino :wink:

if i past in the code i have so far could you help me apply your solutions into it?

After you try, if you have issues, by all means post and ask for help. You need to try though.

PaulS:

if i past in the code i have so far could you help me apply your solutions into it?

After you try, if you have issues, by all means post and ask for help. You need to try though.

Fair enough, Thanks for the motivation! I understand about setting the switches with the state change, but a problem i came across was not being able to press the button thereby changing the function in the middle of the function itself. I had to hold the button until the loop had restarted, this is because in the functions i am using I have delays between LED illumination... So i want to try and overcome that too... This is what i Had Previously:

 //6 LED Chaser Pins 8 - 13 
 
const int LED1 = 13;
const int LED2 = 12;
const int LED3 = 11;
const int LED4 = 10;
const int LED5 = 9;
const int LED6 = 8;   //PIns 8 -13 can be referred to as LEDs 1 - 6

void setup() {                

  pinMode(LED1, OUTPUT); //Sets all the LED's as outputs.
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);

}

void loop()
{
    chaser();            //Runs Function 1 - Chaser
    centerchase();       //Runs Function 2 - Centerchase
}

void chaser()              //The first Function
{                
    digitalWrite(LED1, HIGH);  
  delay(100);              
    digitalWrite(LED1, LOW);
  digitalWrite(LED2, HIGH);
  delay(100); 
    digitalWrite(LED2, LOW);
  digitalWrite(LED3, HIGH);
  delay(100); 
    digitalWrite(LED3, LOW);
  digitalWrite(LED4, HIGH);
  delay(100); 
    digitalWrite(LED4, LOW);
  digitalWrite(LED5, HIGH);
  delay(100); 
    digitalWrite(LED5, LOW);
  digitalWrite(LED6, HIGH);
  delay(100); 
    digitalWrite(LED6, LOW);
  digitalWrite(LED5, HIGH);
  delay(100); 
    digitalWrite(LED5, LOW);
  digitalWrite(LED4, HIGH);
  delay(100); 
   digitalWrite(LED4, LOW);
  digitalWrite(LED3, HIGH);
  delay(100); 
    digitalWrite(LED3, LOW);
  digitalWrite(LED2, HIGH);
  delay(100); 
    digitalWrite(LED2, LOW);   
}

void centerchase() // The second function
{
    digitalWrite(LED1,HIGH);
    digitalWrite(LED6,HIGH);
    delay(100);
    digitalWrite(LED1,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH);
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
    digitalWrite(LED3,HIGH);
    digitalWrite(LED4,HIGH);
    delay(100);
    digitalWrite(LED3,LOW);
    digitalWrite(LED4,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH); 
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
        digitalWrite(LED1,HIGH);
    digitalWrite(LED6,HIGH);
    delay(100);
    digitalWrite(LED1,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH);
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
    digitalWrite(LED3,HIGH);
    digitalWrite(LED4,HIGH);
    delay(100);
    digitalWrite(LED3,LOW);
    digitalWrite(LED4,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH); 
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
}

This is what i had after attempting to add a button in, I used a slihgtly different method but i still dont see why it won't work properly....

 //6 LED Chaser Pins 8 - 13 
 
const int LED1 = 13;
const int LED2 = 12;
const int LED3 = 11;
const int LED4 = 10;
const int LED5 = 9;
const int LED6 = 8;   //PIns 8 -13 can be referred to as LEDs 1 - 6
const int BUTTON = 7; //Pin 7 can be referred to as BUTTON
int val = 0; //Val used to store input of Switch or pin 7
int state = 0; //0 Shows LED off 1 is LED on 
int old_val = 0; // Previous version of val

void setup() 
{                

  pinMode(LED1, OUTPUT); //Sets all the LED's as outputs.
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(BUTTON, INPUT); //Sets Button as input
}

void loop()
{
     val =digitalRead(BUTTON); //Reads the value of the button and stores
     if ((val == HIGH) && (old_val == LOW))
{
      state = 1 - state;  //Check if state has changed 
      delay(10);
}
    old_val = val; // Val is now old val so its stored
          if (state == 1)
{
    chaser();            //Runs Function 1 - Chaser
}
      if (state == 0)
{
    centerchase();       //Runs Function 2 - Centerchase
}

}

void chaser()              //The first Function
{                
    digitalWrite(LED1, HIGH);  
  delay(100);              
    digitalWrite(LED1, LOW);
  digitalWrite(LED2, HIGH);
  delay(100); 
    digitalWrite(LED2, LOW);
  digitalWrite(LED3, HIGH);
  delay(100); 
    digitalWrite(LED3, LOW);
  digitalWrite(LED4, HIGH);
  delay(100); 
    digitalWrite(LED4, LOW);
  digitalWrite(LED5, HIGH);
  delay(100); 
    digitalWrite(LED5, LOW);
  digitalWrite(LED6, HIGH);
  delay(100); 
    digitalWrite(LED6, LOW);
  digitalWrite(LED5, HIGH);
  delay(100); 
    digitalWrite(LED5, LOW);
  digitalWrite(LED4, HIGH);
  delay(100); 
   digitalWrite(LED4, LOW);
  digitalWrite(LED3, HIGH);
  delay(100); 
    digitalWrite(LED3, LOW);
  digitalWrite(LED2, HIGH);
  delay(100); 
    digitalWrite(LED2, LOW);   
}

void centerchase() // The second function
{
    digitalWrite(LED1,HIGH);
    digitalWrite(LED6,HIGH);
    delay(100);
    digitalWrite(LED1,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH);
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
    digitalWrite(LED3,HIGH);
    digitalWrite(LED4,HIGH);
    delay(100);
    digitalWrite(LED3,LOW);
    digitalWrite(LED4,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH); 
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
        digitalWrite(LED1,HIGH);
    digitalWrite(LED6,HIGH);
    delay(100);
    digitalWrite(LED1,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH);
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
    digitalWrite(LED3,HIGH);
    digitalWrite(LED4,HIGH);
    delay(100);
    digitalWrite(LED3,LOW);
    digitalWrite(LED4,LOW);
    digitalWrite(LED2,HIGH);
    digitalWrite(LED5,HIGH); 
    delay(100);
    digitalWrite(LED2,LOW);
    digitalWrite(LED5,LOW);
}

What the above does is getting there, when i press the button it will switch to the other function, BUT i have to HOLD ON the button until the end of each function cycle before it will register the state change. I took a video of the circuit using 6 leds. Shown below: (Photobucket upload)

I understand about setting the switches with the state change, but a problem i came across was not being able to press the button thereby changing the function in the middle of the function itself. I had to hold the button until the loop had restarted, this is because in the functions i am using I have delays between LED illumination.

Those delay()s will kill you every time.

Think about how you would manage the LEDs switching, with a pad of paper and a watch. Pretend that the delay() was 30 minutes, instead.

You would switch an LED on, and you could stare at the watch until 30 minutes had passed. That's what delay() does.

Or, you could switch the LED on, write down the time, and go have a beer and watch a ball game. Periodically, you would need to go see if half an hour had elapsed. If so, do something, and write down the time.

The blink without delay example tries, not very well, to illustrate this second way.

Instead of the Arduino going and having a beer and watching the ball game, it is going and checking the switch state, so the change can be noticed much more quickly.

In your two functions, which you would still call just like you do now, the delays need to be removed, and millis() used to determine when a state change needs to occur, just as Marek080 suggested. When the state change occurs, perform some action, and note the time.

One of the function will be called a lot more often, but, in the end it won't do any more work. It's just that most of the time, the function will simply return (just as if you checked the watch every second, to see if the 30 minutes was up).

As PaulS already described in a very good way, you have to rebuild your functions for the led changing. Basically you do the same state machine building in chaser() and centerchase() as I proposed for loop(), but now you do not have to call functions but could just insert your digitalWrite() calls into the switch.

You will end up with a counter/state which changes every 100ms (there you use millis() for the comparison) and a big switch. Every case of the switch changes some LEDs and that's all until the next 100ms passed.

And you still have a delay() in the main loop. Try to use switch instead of if statements (and do not forget the break statements).

Your loop() could look like the following - easier to read, isn't it:

void loop()
{
  val =digitalRead(BUTTON); //Reads the value of the button and stores
  if ((val == HIGH) && (old_val == LOW))
  {
    state = 1 - state;  //Check if state has changed 
    // delay(10);
  }
  old_val = val; // Val is now old val so its stored

  switch(state)
  {
    case 1:
      chaser();            //Runs Function 1 - Chaser
      break;
    case 0:
      centerchase();       //Runs Function 2 - Centerchase
      break;
  }
}

and please use "Auto Format" in the Tools menu.

PaulS:

I understand about setting the switches with the state change, but a problem i came across was not being able to press the button thereby changing the function in the middle of the function itself. I had to hold the button until the loop had restarted, this is because in the functions i am using I have delays between LED illumination.

Those delay()s will kill you every time.

Think about how you would manage the LEDs switching, with a pad of paper and a watch. Pretend that the delay() was 30 minutes, instead.

You would switch an LED on, and you could stare at the watch until 30 minutes had passed. That's what delay() does.

Or, you could switch the LED on, write down the time, and go have a beer and watch a ball game. Periodically, you would need to go see if half an hour had elapsed. If so, do something, and write down the time.

The blink without delay example tries, not very well, to illustrate this second way.

Instead of the Arduino going and having a beer and watching the ball game, it is going and checking the switch state, so the change can be noticed much more quickly.

In your two functions, which you would still call just like you do now, the delays need to be removed, and millis() used to determine when a state change needs to occur, just as Marek080 suggested. When the state change occurs, perform some action, and note the time.

One of the function will be called a lot more often, but, in the end it won't do any more work. It's just that most of the time, the function will simply return (just as if you checked the watch every second, to see if the 30 minutes was up).

That makes sense, but My head is not clicking today, I really appreciate your help, but i'm going to start with a fresh mind tomorrow and hopefully i can edit my code sucessfully!
Thanks!

but i'm going to start with a fresh mind tomorrow

When you do, start by playing computer for a few minutes. Write down the exact steps YOU would need to do the make the LEDs behave in the way you want, without the need to stare at your watch. Remember that if the Arduino is a millisecond or two late toggling some LEDs, you will not notice that. Also, remember that it is fast at executing most code, so it won't be late, unless you delay() it. So, don't.