Recycling code via subroutines?

Hi all,

I am trying to learn how to use subroutines and I am struggling with passing variables. I would like to learn the correct way (if there is such a thing) rather than ending up with spaghetti code.

The basic concept is to use the "debounce" example code as a subroutine for multiple push buttons on different pins. I understand that I can pass the pin number to read to the subroutine and how to return the state, the issue is how you handle the timing elements of the code to reference the timing for each button. Do I have to create global variables and assign each subroutine variable before the subroutine is called and then assign them back to the desired variable? I am sure there is an easier way.

I am struggling to even write some example code to post and was hoping someone may have some code similar that I could study and learn.

As always, your educational help is greatly appreciated. :slight_smile:

I am sure there is an easier way.

You could pass variables by reference rather than by value so that the function can read and change the values. A little reading will help you understand the difference

Hi Mate,
Reading that again and I think I could have written that a little better, What I am thinking for now with the variables is like the following but I am sure there is a better way and I always want to improve my knowledge :slight_smile:

I just wrote this as a concept:-

// constants won't change. They're used here to set pin numbers:
const int buttonPinOne = 2;    // the number of the pushbutton pin
const int buttonPinTwo = 3;
const int ledPinOne = 13;      // the number of the LED pin
const int ledPinTwo = 12;

// Variables will change:
int ledPin;
int ledState = HIGH;         // the current state of the output pin
int ledStateOne = HIGH;
int ledStateTwo = HIGH;
int buttonState;
int lastButtonState = LOW;
int buttonStateOne;
int lastButtonStateOne = LOW;
int buttonStateTwo;
int lastButtonStateTwo = LOW;

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;
unsigned long lastDebounceTimeOne = 0;
unsigned long lastDebounceTimeTwo = 0;
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPinOne, INPUT);
  pinMode(buttonPinTwo, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);
}

void loop() {

  ledState = debounce(buttonPinOne, buttonStateOne, lastButtonStateOne, lastDebounceTimeOne);
  ledSet(ledPinOne,ledState);         // Do code

  buttonStateOne = buttonState;
  lastButtonStateOne = lastButtonState;
  lastDebounceTimeOne = lastDebounceTime;  // Save any changes to variable set one

  ledState = debounce(buttonPinTwo, buttonStateTwo, lastButtonStateTwo, lastDebounceTimeTwo);
  ledSet(ledPinTwo,ledState);        // do code

   buttonStateTwo = buttonState;
  lastButtonStateTwo = lastButtonState;
  lastDebounceTimeTwo = lastDebounceTime; // save any changes to variable set two


  
}

int debounce(int buttonPin, int buttonState, int lastButtonState, int LastDebounceTime) {

  int reading = digitalRead(buttonPin);

  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {

    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }
  lastButtonState = reading;
  return ledState;

}

void ledSet(int ledPin, int ledState){
// set the LED:
  digitalWrite(ledPin, ledState);  
}

Beginners way...
Define a structure containing all your variables, pass a reference to the structure to the function.

Advanced way...
Create your own class.

There are several debounce libraries in IDE -> file/sketch/include library/manage libraries. Look at other's code to see how they did it.

One problem with a single function for debounce is that it generally will also include state change detection. If you return HIGH/LOW from the function there is no way for the calling code to know if this was a state change without doing an additional state change detection. If state change detection is needed you will probably want a separate function that returns CHANGED_HIGH, CHANGED_LOW, or UNCHANGED. Since you now have two functions operating on the same data you have even more reason to define an object class.

And then there is the common case of a button that toggles a state. Another member function for the object.

And detecting long press vs short press...

I think a class definition is the best way to go. :slight_smile:

Wow,
I have started to research classes and I think this will be the avenue I need to head down. As mentioned above, this is not so much for a functioning end result, more fore my own education of C++ and the best way to implement different types of functions. I really appreciate the guidance these forums give.

Thanks Again,
Scary

i have an application that monitors a number of buttons. chkButtons() checks a list of pins in an array, sets a butPress which is cleared each iteration and set when a button change occurs and the button state is low. it also returns a true result if any button is pressed used as an abort for things that might block.

in my tiny application (~ 2400 lines), butPress is used globally (or at least globally w/in the file). in a much larger application, butPress could be hidden and a separate function called to check if a particular button was pressed.

for my applications, i simply delay for 10 msec if there is a button state change to debounce