Help - trying to understand creating a function

I am trying to create some function code so that I can reuse the same function multiple times for different input (buttons). I was thinking this would speed up program execution and reduce the complexity of the overall code (maybe not?)

As an example I am trying to have a piece of code that can toggle a state based on button press that could be called at different times for a check of several different input buttons... if that makes sense

Here's where I am so far - but now I have writers block and am thinking it maybe isn't the correct method?

#define enableButton 11


int toggleState = HIGH;
int previousToggleState = LOW;
long toggleButtonTime = 0;
long buttonDebounce = 200;
int outputLED = 13;
int output;


String toggleButton (String buttonType, String output)
{
  if (toggleState == LOW && previousToggleState == HIGH && millis() - toggleButtonTime > buttonDebounce)
  {
    if (toggleState == LOW)
      toggleState = HIGH;
    else
      toggleState = LOW;
    toggleButtonTime = millis();
  }
}
void setup() {
  // put your setup code here, to run once:
  pinMode (enableButton, INPUT_PULLUP);
  pinMode (jogCWButton, INPUT_PULLUP);
  pinMode (jogCCWButton, INPUT_PULLUP);
  pinMode (outputLED, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  toggleButton("enableButton", "outputLED");
  digitalWrite(output, toggleState);
  Serial.print(enableButton);
  Serial.println(" pressed");
  Serial.print("Output - ");
  Serial.println(output);
  Serial.print("State - ");
  Serial.println(toggleState);
}
String toggleButton (String buttonType, String output)

In some languages, everything is a String. In the Arduino, that's a very "expensive" variable type. So expensive that it can crash your entire program by running out of memory if you do things which appear normal in those stringy languages.

So buttons which can be on or off usually use a much smaller type like boolean.

Your function refers to several global variables such as previousToggleState. But if you have several buttons, you are going to have to remember several previous states. One global isn't going to work. Many globals is a bad idea - you end up with a lot of copy-paste code which is what you wanted to avoid in the first place.

There are a number of ways to go but I would like to suggest you use a class to represent a button. The class can contain the previousToggleState and the functions which work upon those variables. By having more than one instance of the class you can have several buttons, which keep track of their own states internally, without using global variables.

It looks like you want to name the buttons with the String buttonType. You can put a name String or string in the class if you want.

what you are describing could be solved with loops and arrays.

if you store your pin numbers and previos states in arrays. you can page through the indexes in a loop
and repeat the same code for each pin. here is a very basic button example.

  // create 4 bools to store previos readings 
  bool lasts[4];
  // store pin number in an array
  int  pins[4]={2,3,4,6};
 
  
void loop() {

  int i = 0;
  while(i<4){
// this loop happens 4 times
// variable "i" will count  from 0 to 3
   
  bool reading = digitalRead(pins[i]); 

  if(reading!=lasts[i]){// check for change
    
        if(reading==LOW){// check for down

        // button detected on this pin
         Serial.println(pins[i]);
        
         }
    lasts[i]=reading;
     }
  i++;
}
}

I keep the following sketch as a template.

Because it's delay()-less (ok, well apart from a tiny ersatz debounce) you can press and hold a button then press another while first is held and see that the two are pressed, then release one, press and hold a third etc etc (fingers permitting) in any sequence. Bwod on L13 to prove there's no delay()s.

No need to specify how many buttons there are, it uses sizeof() to find out for itself.

If you act on the fact that a button is newly pressed or released, remember to clear its flag.

buttonIsNewlyPressed[i] = false;
buttonIsNewlyReleased[i] = false;
// state change detect on a button array
// 30 august 2019
// has blink-without-delay on pin13 to prove no blocking

// the buttons
byte buttonPins[] = {8, 9, 10}; //the buttons must be wired from pin to ground, pinmodes are input_pullup
const byte howManyButtons(sizeof(buttonPins) / sizeof(byte));
bool buttonStates[howManyButtons];         // current state of the button
bool lastButtonStates[howManyButtons];     // previous state of the button
bool buttonIsNewlyPressed[howManyButtons];
bool buttonIsNewlyReleased[howManyButtons];

//the bwod led
int bwodLedInterval = 500;
unsigned long previousMillisBwod;
bool bwodState = false;

void setup()
{
  // initialize serial communication:
  Serial.begin(9600);
  Serial.println("setup() ... ");
  Serial.println(".... state change detect on a button array ....");
  Serial.print("Compiler: ");
  Serial.print(__VERSION__);
  Serial.print(", Arduino IDE: ");
  Serial.println(ARDUINO);
  Serial.print("Created: ");
  Serial.print(__TIME__);
  Serial.print(", ");
  Serial.println(__DATE__);
  Serial.println(__FILE__);
  Serial.println(" ");

  // initialize the button pins as input with pullup so active low
  //    make sure the button is from pin to ground
  Serial.println("Should show button, pin, 1100:");
  for (int i = 0; i < howManyButtons; i++)
  {
    pinMode(buttonPins[i], INPUT_PULLUP);
    //initialize button states
    buttonStates[i] = digitalRead(buttonPins[i]);
    lastButtonStates[i] = buttonStates[i];
    buttonIsNewlyPressed[i] = 0;
    buttonIsNewlyReleased[i] = 0;
    Serial.print(i);
    Serial.print(", ");
    Serial.print(buttonPins[i]);
    Serial.print(", ");
    Serial.print(buttonStates[i]);
    Serial.print(lastButtonStates[i]);
    Serial.print(buttonIsNewlyPressed[i]);
    Serial.print(buttonIsNewlyReleased[i]);  //should show button, pin, then 1100
    Serial.println("");
  }
  //initialise pulse led
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, bwodState);

  Serial.println("setup() done");
  Serial.println("Press a button....");
  Serial.println(" ");
}

void loop()
{
  bwod();
  checkForButtonStateChange();
  doSomeThingWithANewlyPressedButton();
  doSomeThingWithANewlyReleasedButton();
} //loop

void checkForButtonStateChange()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    buttonStates[i] = digitalRead(buttonPins[i]);
    // compare the buttonState to its previous state
    if (buttonStates[i] != lastButtonStates[i]) // means it changed... but which way?
    {
      if (buttonStates[i] == LOW)  // changed to pressed
      {
        Serial.print(i);
        Serial.println(" newly pressed");
        buttonIsNewlyPressed[i] = true;
      }
      else  // changed to released
      {
        // if the current state is HIGH then the button was released
        Serial.print("   ");
        Serial.print(i);
        Serial.println(" newly released");
        buttonIsNewlyReleased[i] = true;
      }
      // ersatz de-bounce
      delay(50);
    }
    // save the current state as the last state, for next time through the loop
    lastButtonStates[i] = buttonStates[i];
  }
} // checkForButtonStateChange()

void doSomeThingWithANewlyPressedButton()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    if (buttonIsNewlyPressed[i])
    {
      Serial.print("Using the new press of button ");
      Serial.println(i);
      buttonIsNewlyPressed[i] = false;
    }
  }
}//doSomeThingWithANewlyPressedButton

void doSomeThingWithANewlyReleasedButton()
{
  for (int i = 0; i < howManyButtons; i++)
  {
    if (buttonIsNewlyReleased[i])
    {
      Serial.print("   Using the new release of button ");
      Serial.println(i);
      buttonIsNewlyReleased[i] = false;
    }
  }
}//doSomeThingWithANewlyReleasedButton

void bwod()
{
  if (millis() - previousMillisBwod >= bwodLedInterval)
  {
    previousMillisBwod = millis();
    bwodState = !bwodState;
    digitalWrite(LED_BUILTIN, bwodState);
  }
} //bwod

Sample output:

setup() ... 
.... state change detect on a button array ....
Compiler: 4.9.2, Arduino IDE: 10805
Created: 06:35:44, Nov 15 2019
C:\Users\sayHovis\Documents\Arduino\statechangedetect_array\statechangedetect_array.ino
 
Should show button, pin, 1100:
0, 8, 1100
1, 9, 1100
2, 10, 1100
setup() done
Press a button....
 
0 newly pressed
Using the new press of button 0
2 newly pressed
Using the new press of button 2
   0 newly released
   Using the new release of button 0
1 newly pressed
Using the new press of button 1
   2 newly released
   Using the new release of button 2
   1 newly released
   Using the new release of button 1

The above is very useful in switch...case based state machines. There I would probably ditch the functions doSomeThingWithANewlyPressedButton() and doSomeThingWithANewlyReleasedButton() but rather check explictly for the press or release of a particular button in the appropriate cases.

So I would still checkForButtonStateChange() at the top of loop(), and then in switch...case do something like this pseudocode:

case machineIsIdle
   if (buttonIsNewlyPressed[4])
      { 
         do some stuff
         buttonIsNewlyPressed[4]=false;
      }

    if (buttonIsNewlyReleased[6])
      { 
         do some other stuff
         buttonIsNewlyReleased[6]=false;
      }

case machineIsRunning
 if (buttonIsNewlyPressed[3])
      { 
         do yet some more stuff
         buttonIsNewlyPressed[3]=false;
      }