switch statment changes for no reason?

Ok, so I have a mode set by an analog button (this is the multi-button over 1 analog wire setup)
and for some reason “sysMode” the mode selector changes without any input after it’s been set to a mode IE: 1 2 or 3

Example, so I’ll press one of the 3 buttons, it goes from idle to that mode. Let it sit in that loop for a while and it’ll just drop out back to idle after about 45 seconds to like a min and half something like that, and that’s if the thing doesn’t reboot after a bit sometimes.

Any ideas? Thoughts?

Board: Uno R3

// INCLUDES
#include <LiquidCrystal.h>

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 0;     // the number of the pushbutton pin
const int ledPinbut1 =  9;      // the number of the LED pin for testing
const int ledPinbut2 =  13;      // the number of the LED pin for testing
const int ledPinbut3 =  10;      // the number of the LED pin for testing
int HBLed = A1; // Heartbeat

// all of our LCD pins
int lcdRSPin = 12;
int lcdEPin = 11;
int lcdD4Pin = 5;
int lcdD5Pin = 4;
int lcdD6Pin = 3;
int lcdD7Pin = 2;

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(lcdRSPin, lcdEPin, lcdD4Pin, lcdD5Pin, lcdD6Pin, lcdD7Pin);

const int BUTTON1 = 1;
const int BUTTON2 = 2;
const int BUTTON3 = 3;
int reading = 0; // set the val for analog reading

// BUTTON ANALOG RANGES
const int BUTTON1LOW = 570;
const int BUTTON1HIGH = 620;
const int BUTTON2LOW = 925;
const int BUTTON2HIGH = 935;
const int BUTTON3LOW = 765;
const int BUTTON3HIGH = 780;

//MODE SELECTOR
int sysMode = 0;

//DEBUG MODES
// 0 = OFF
// 1 = ADC READOMG
// 2 = sysMode Selection Status
int RDbug = 2;

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 150;    // the debounce time; increase if the output flickers

void setup() {
    // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.clear();

  lcd.print("System Boot...");
  lcd.setCursor(0, 0); 
  delay(1000);

  lcd.setCursor(0, 1); 
  lcd.print("Setting up");
  delay(50);
     
  pinMode(buttonPin, INPUT);
  pinMode(ledPinbut1, OUTPUT);
  pinMode(ledPinbut2, OUTPUT);
  pinMode(ledPinbut3, OUTPUT);
  pinMode(A1, OUTPUT);
  //Serial.begin(115200);
  
  // System Ready NOTHING after this... //
  lcd.setCursor(0, 1); 
  lcd.print("System Ready");
  delay(500);
  lcd.clear();
}

/////////////////////////// - MAIN LOOP - /////////////////////////////////
void loop() {
  //delay(100);
  hb();
  chkbuts(sysMode);
}


///////////////////////// - SYS FUNCTIONS - ///////////////////////////////
void mode1(){
  sysMode = 1;
  digitalWrite(9, HIGH);

  if (RDbug == 2){
    Serial.println("Mode 1");
  }
  delay(50);
  //digitalWrite(9, LOW);
  chkbuts(sysMode);
}

void mode2(){
  sysMode = 2;
  digitalWrite(13, HIGH);

  if (RDbug == 2){
    Serial.println("Mode 2");
  }
  delay(50);
  //digitalWrite(13, LOW);
  chkbuts(sysMode);
}

void mode3(){
  sysMode = 3;
  digitalWrite(10, HIGH);

  if (RDbug == 2){
    Serial.println("Mode 3");
  }
  delay(50);
  //digitalWrite(10, LOW);
  chkbuts(sysMode);
}




//////////////////////////- CHECK BUTTONS -///////////////////////////////
void chkbuts(int sysMode){
  // read the state of the switch into a local variable:
//  int reading = analogRead(buttonPin);
  reading = analogRead(buttonPin);

  //
  if (RDbug == 1){
    Serial.print("ADC Reading: ");  
    Serial.println(reading);
  }

  //delay(50);
  int tmpButtonState = LOW;             // the current reading from the input pin

  if(reading>BUTTON1LOW && reading<BUTTON1HIGH){
    //Read switch 1
    tmpButtonState = BUTTON1;
  }
  else if(reading>BUTTON2LOW && reading<BUTTON2HIGH){
    //Read switch 2
    tmpButtonState = BUTTON2;
  }
  else if(reading>BUTTON3LOW && reading<BUTTON3HIGH){
    //Read switch 3
    tmpButtonState = BUTTON3;
  }
  else if(tmpButtonState!=LOW){
    tmpButtonState = tmpButtonState;
  }
  else if(sysMode!=0 && tmpButtonState==LOW) {
    //Mode continues no new button pressed
    sysModeChecker(sysMode);
  }
  else{
    //No button is pressed;
    tmpButtonState = LOW;
    Serial.print("sysMode:");
    Serial.println(sysMode);
  }

  // check to see if you just pressed the button 
  // (i.e. the input went from LOW to a buttonState),  and you've waited 
  // long enough since the last press to ignore any noise:  

  // If the switch changed, due to noise or pressing:
  if (tmpButtonState != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  } 

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer
    // than the debounce delay, so take it as the actual current state:
    buttonState = tmpButtonState;
  }

  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
  lastButtonState = tmpButtonState;

  //
  // HERE WE HAVE A NEW INPUT AND WE ARE GOING TO ENTER A MODE BASED ON NEW INPUT
  //
  switch(buttonState){
  case LOW:
    digitalWrite(ledPinbut1, LOW);
    digitalWrite(ledPinbut2, LOW);
    digitalWrite(ledPinbut3, LOW);  
    sysMode=0; // if we get here, let's reset sysMode to nothing
    clearumodes(sysMode);
    //chkbuts(sysMode); // we have resetted the LEDS to off and now we are going to button check again
    break;
  case BUTTON1:
    clearumodes(sysMode);
    mode1(); // run mode one
    break;
  case BUTTON2:
    clearumodes(sysMode);
    mode2(); // run mode two
    break;
  case BUTTON3:
    clearumodes(sysMode);
    mode3(); // run mode three
    break;
  }
}




//
// HERE WE HAVE NO NEW INPUT SO WE ARE GOING TO RUN THE MODE SELECTOR TO KEEP OUR MODE RUNNING
//
void sysModeChecker(int sysMode){
  //delay(50);
  switch(sysMode){
  case 1:
    clearumodes(sysMode);
    mode1();
    break;
  case 2:
    clearumodes(sysMode);
    mode2();
    break;
  case 3:
    clearumodes(sysMode);
    mode3();
    break;
  }
}



//
// This turns off the mode lights of modes that are not on. 
// Without this when you switch modes the prev mode light would stay on
//
void clearumodes(int sysMode){
  hb();
  switch(sysMode){
  case 0:
    digitalWrite(ledPinbut1, LOW);
    digitalWrite(ledPinbut2, LOW);
    digitalWrite(ledPinbut3, LOW);  
    break;
  case 1:
    digitalWrite(ledPinbut1, HIGH);
    digitalWrite(ledPinbut2, LOW);
    digitalWrite(ledPinbut3, LOW);  
    break;
  case 2:
    digitalWrite(ledPinbut1, LOW);
    digitalWrite(ledPinbut2, HIGH);
    digitalWrite(ledPinbut3, LOW);  
    break;
  case 3:
    digitalWrite(ledPinbut1, LOW);
    digitalWrite(ledPinbut2, LOW);
    digitalWrite(ledPinbut3, HIGH);  
    break;
  }
}

void hb(){
  //delay(50);
  digitalWrite(A1, HIGH);
  delay(100);
  digitalWrite(A1, LOW);
  delay(100);
  //delay(25);
  //digitalWrite(A1, HIGH);
  //delay(100);
  //digitalWrite(A1, LOW);
  //delay(50);
  lcdupdate();
}

void lcdupdate(){
  lcd.clear();
  lcd.setCursor(0, 0); 
  lcd.print("sysMODE: ");
  lcd.print(sysMode);
  ///////////////////////////////
  lcd.setCursor(0, 1); 
  lcd.print("READ: ");
  lcd.print(reading);
}

How are you wiring your button? Is there pull up or down resistor? Why are you reading them with analogue read?

The code looks very very complicated for doing such a simple thing.

Buttonstate does not seem to be set to anything if there is no button pressed.

The buttons work kind of like this

http://www.instructables.com/id/How-to-access-5-buttons-through-1-Arduino-input/

It knows a button is pushed when a number in the range is triggered.

That's not the problem, it works great.

The problem is something with the way I'm looping. I need this to basically switch loops and stay in the new loop until told to jump to another loop.

But right now as it is, it will only stay in a "mode" for about 40 seconds and then just drops out to mode 0

it also seems to reset every now and then...

I mean the easy fix is just to use switches rather than buttons and then I don't have to check for button pushes, but this should work, I'm wondering why it falls back to idle

t also seems to reset every now and then…

What resets?

like the microcontroler, as if it software reboots because of load?

You've got functions calling each other recursively.

chkbuts() calls the mode functions in the statement switch(buttonState).

Then the mode functions call chkbuts() ...

void mode1(){
  sysMode = 1;
  digitalWrite(9, HIGH);

  if (RDbug == 2){
    Serial.println("Mode 1");
  }
  delay(50);
  //digitalWrite(9, LOW);
  chkbuts(sysMode);
}

This will cause the program to run out of memory.

yes that's so it just runs the same mode again rather than mode 2 function ending and going back to void loop...

unless it doesn't work that way?

GodFear17:
yes that’s so it just runs the same mode again rather than mode 2 function ending and going back to void loop…

unless it doesn’t work that way?

It will work that way, but only until you run out of memory. And you WILL run out of memory.

When you call a function, the return address and possibly other values are pushed onto the stack. When you return from a function, the values pushed onto the stack are popped off the stack, and the program continues at the return address.

If you call that same function again, without returning from the first call to the function, you will not pop the values off the stack. So you keep calling chkbuts() without ever returning from it, over and over, each time leaving at minimum, the return address on tha stack.

So, your stack keeps on growing, and eventually, you run out of stack room and overwrite some variables. Boom!

ahh so it's a memory leak?

So how would I state machine this so that you change modes and it stays in that mode?

GodFear17: ahh so it's a memory leak?

Indeed it is.

So how would I state machine this so that you change modes and it stays in that mode?

  loop () {
     check buttons
     if new button pressed {
          set state
     }
     switch case state {
          do stuff for appropriate state
     }
  }

In other words, do nothing until a button is pressed. then, keep doing state code (or do it once, but only when state changes) repeat.

Thanks for the help guys! After removing the function call in the modes it works great. Doesnt reboot and runs without stopping.