Assigning multiple Buttons and LEDs and having a 1->1 relationship.

Hi all,

I'm currently in the testing phase of a digitally controlled analog system and I am using LEDs to get a proof of concept.

to start with I need x about of LEDs each having a dedicated button to switch the LED state between on and off. I am able to do this successfully with a single LED and button and it should be easy enough to copy and paste my code to add more, but that is going to get messy pretty fast.

I have made a small amount of progress and figured out how to easily assign multiple pins as inputs and outputs. Here is my current code with one button controlling multiple LEDs.

int ledPins[] = {
 8, 9, 10, 11, 12, 13
};       // an array of pin numbers to which LEDs are attached
int pinCount = 6;           // the number of pins (i.e. the length of the array)
int Button = 2;

int LedState = LOW;
int ButtonCurrent;
int ButtonPrev = HIGH; // has to be opposite of led.



void setup() {
 // the array elements are numbered from 0 to (pinCount - 1).
  // use a for loop to initialize each pin as an output:
  for (int thisPin = 0; thisPin < pinCount; thisPin++) {
    pinMode(ledPins[thisPin], OUTPUT);
  }
  pinMode(Button, INPUT_PULLUP);
}

void loop() {
  
  ButtonCurrent = digitalRead (Button); // Read current button state.

  if(ButtonCurrent == HIGH && ButtonPrev == LOW) // if statement starts when button is pressed. and changes led state to the opposit of its current state.
    {
    if (LedState == HIGH)
    {
    LedState = LOW;
    }
    else 
    {
      LedState = HIGH;
    }
  }
for (int thisPin = 0; thisPin < pinCount; thisPin++) { // apply LedState to all LED OUTPUTS.
  digitalWrite(ledPins[thisPin], LedState);
  }
  ButtonPrev = ButtonCurrent;
}

I can just as easily assign multiple pins as outputs, but I can not figure out how to approach having button1 switch only LED1, etc.

Once I figure that out, the actual end goal is to be able to save and load different LED arrangements as presets.

Any input is much appreciated.

more or less you will need also an array for your LedState and remember each LED individually.

// Radio Buttons!
const int led1Pin =  3;    // LED pin number
const int button1 =  2;
const int led2Pin =  5;
const int button2 =  4;
const int led3Pin =  6;
const int button3 =  7;
const int led4Pin =  9;
const int button4 =  8;
char bstate1 = 0;
char bstate2 = 0;
char bstate3 = 0;
char bstate4 = 0;
unsigned long bcount1 = 0; // button debounce timer.  Replicate as necessary.
unsigned long bcount2 = 0;
unsigned long bcount3 = 0;
unsigned long bcount4 = 0;


// Have we completed the specified interval since last confirmed event?
// "marker" chooses which counter to check
// Routines by Paul__B of Arduino Forum
boolean timeout(unsigned long *marker, unsigned long interval) {
  if (millis() - *marker >= interval) {
    *marker += interval;    // move on ready for next interval
    return true;
  }
  else return false;
}

// Deal with a button read; true if button pressed and debounced is a new event
// Uses reading of button input, debounce store, state store and debounce interval.
// Routines by Paul__B of Arduino Forum
boolean butndown(char button, unsigned long *marker, char *butnstate, unsigned long interval) {
  switch (*butnstate) {               // Odd states if was pressed, >= 2 if debounce in progress
    case 0: // Button up so far,
      if (button == HIGH) return false; // Nothing happening!
      else {
        *butnstate = 2;                 // record that is now pressed
        *marker = millis();             // note when was pressed
        return false;                   // and move on
      }

    case 1: // Button down so far,
      if (button == LOW) return false; // Nothing happening!
      else {
        *butnstate = 3;                 // record that is now released
        *marker = millis();             // note when was released
        return false;                   // and move on
      }

    case 2: // Button was up, now down.
      if (button == HIGH) {
        *butnstate = 0;                 // no, not debounced; revert the state
        return false;                   // False alarm!
      }
      else {
        if (millis() - *marker >= interval) {
          *butnstate = 1;               // jackpot!  update the state
          return true;                  // because we have the desired event!
        }
        else
          return false;                 // not done yet; just move on
      }

    case 3: // Button was down, now up.
      if (button == LOW) {
        *butnstate = 1;                 // no, not debounced; revert the state
        return false;                   // False alarm!
      }
      else {
        if (millis() - *marker >= interval) {
          *butnstate = 0;               // Debounced; update the state
          return false;                 // but it is not the event we want
        }
        else
          return false;                 // not done yet; just move on
      }
    default:                            // Error; recover anyway
      {
        *butnstate = 0;
        return false;                   // Definitely false!
      }
  }
}

void setup() {
  pinMode(led1Pin, OUTPUT);
  pinMode(button1, INPUT_PULLUP);
  pinMode(led2Pin, OUTPUT);
  pinMode(button2, INPUT_PULLUP);
  pinMode(led3Pin, OUTPUT);
  pinMode(button3, INPUT_PULLUP);
  pinMode(led4Pin, OUTPUT);
  pinMode(button4, INPUT_PULLUP);
  digitalWrite (led1Pin, LOW);
  digitalWrite (led2Pin, LOW);
  digitalWrite (led3Pin, LOW);
  digitalWrite (led4Pin, LOW);
}

void loop() {
  // Select LED if button debounced
  if (butndown(digitalRead(button1), &bcount1, &bstate1, 10UL )) {
    digitalWrite (led1Pin, HIGH);
    digitalWrite (led2Pin, LOW);
    digitalWrite (led3Pin, LOW);
    digitalWrite (led4Pin, LOW);
  }
  // Select LED if button debounced
  if (butndown(digitalRead(button2), &bcount2, &bstate2, 10UL )) {
    digitalWrite (led1Pin, LOW);
    digitalWrite (led2Pin, HIGH);
    digitalWrite (led3Pin, LOW);
    digitalWrite (led4Pin, LOW);
  }
  // Select LED if button debounced
  if (butndown(digitalRead(button3), &bcount3, &bstate3, 10UL )) {
    digitalWrite (led1Pin, LOW);
    digitalWrite (led2Pin, LOW);
    digitalWrite (led3Pin, HIGH);
    digitalWrite (led4Pin, LOW);
  }
  // Select LED if button debounced
  if (butndown(digitalRead(button4), &bcount4, &bstate4, 10UL )) {
    digitalWrite (led1Pin, LOW);
    digitalWrite (led2Pin, LOW);
    digitalWrite (led3Pin, LOW);
    digitalWrite (led4Pin, HIGH);
  }
}

Thanks, Paul __B I'm going to take a good look at your debounce as I haven't got into that yet.

I'm specifically trying to use arrays so I don't have to assign so many integers. noiasca suggested just the right thing. Here is my updated code

int ledPins[] = {
 8, 9, 10, 11, 12, 13
  };                         // an array of pin numbers to which LEDs are attached
  int LedState[]{ 
  0, 1, 2, 3, 4, 5          // state corrisponding to each LED
  };
int pinCount = 6;           // the number of LEDs (i.e. the length of the array)

int Button[] = {
2, 3, 4, 5, 6, 7
  };
int ButtonCurrent[] = {
  0, 1, 2, 3, 4, 5         // Button Pins
 };
int ButtonPrev[] = {
  0, 1, 2, 3, 4, 5
 };
 int ButtonCount = 6;





void setup() {
 // the array elements are numbered from 0 to (pinCount - 1).
  
  for (int i = 0; i < pinCount; i++) {
    pinMode(ledPins[i], OUTPUT);      // use a for loop to initialize each pin as an output:
  }
  for (int i = 0; i < ButtonCount; i++) {
  pinMode(Button[i], INPUT_PULLUP);       // use a for loop to initialize each pin as an input
  }
  for (int i = 0; i < pinCount; i++) {
digitalWrite ( LedState[i], LOW);       // use a for loop to initialize all LED states LOW
  }
  for (int i = 0; i < pinCount; i++) {
digitalWrite ( ButtonPrev[i], HIGH);// has to be opposite of led.
  }
}

void loop() {

  for (int i = 0; i < ButtonCount; i++) {
  ButtonCurrent[i] = digitalRead (Button[i]); // Read current button state for all buttonsin array.
  }
 
  for (int i = 0; i < ButtonCount; i++) {
  if(ButtonCurrent[i] == HIGH && ButtonPrev[i] == LOW) // if statement starts when button is pressed. and changes led state to the opposit of its current state.
    {
    if (LedState[i] == HIGH)
    {
    LedState[i] = LOW;
    }
    else 
    {
      LedState[i] = HIGH;
    }
    }
  }
for (int i = 0; i < pinCount; i++) { // apply LedState to corresponding LED OUTPUTS.
  digitalWrite(ledPins[i], LedState[i]);
  }
  for (int i = 0; i < ButtonCount; i++) {
  ButtonPrev[i] = ButtonCurrent[i];
  }
}

I suspect it's still a bit rudimentary as each button and LED combination are fixed to each other and I cant let say Button 5 switch LED 1 or change combinations. But that's beyond the scope of this test, for now, I have each button switching a dedicated LED without affecting the state of the others!

reinerterig:
and I cant let say Button 5 switch LED 1 or change combinations.

Yes, you can!

just bring the content (the pins) of Button[] in the right order.
you don't have to start with the lowest Pin-Number in index 0...

Won't that always just go up in succession?

So in that example, if I start on button 5 for LED 1, LED 2 would be button 6, LED 3 Would be button 1, LED 4 button 2, LED 5 button 3 and LED 6 button 4?

Now I'm curious if I can assign any button to any LED.

what ever your desired order is. resp. the order yo want

int Button[] = {2, 3, 4, 5, 6, 7 };

or

int Button[] = {5, 3, 6, 2, 7, 4};

you are the programmer - May the Force be with you!

just give it a try!

reinerterig:
I have each button switching a dedicated LED without affecting the state of the others!

Well, that is partly because of good luck. Your code contains several errors and indicates you are still quite confused. If you would like to know why, please ask.

PaulRB:
Well, that is partly because of good luck. Your code contains several errors and indicates you are still quite confused. If you would like to know why, please ask.

Of course I am still confused :sweat_smile: and help would very much be appreciated!

Ok, here's one to get you thinking:

  int LedState[]{ 
  0, 1, 2, 3, 4, 5          // state corrisponding to each LED
  };

What values should the state of a led be? I would think HIGH or LOW. What would a state of 4 mean, for example? What about BuutonCurrent and ButtonPrev?

Here's another:

digitalWrite ( LedState[i], LOW);

I assume LedState should HIGH or LOW, indicating if a led is on or off? It's not an Arduino pin number. Because of the way the Arduino language works, HIGH is 1 and LOW is 0. So this line sets Arduino pins 0 and 1 to LOW. These are the pins used to upload sketches and communicate with Serial Monitor (on most Arduino like Uno) and you should not be setting those pins to anything. Plus, at the moment, LedState contains 0 to 5, so Arduino pins 0 to 5 will be set to LOW, and I don't think that's what you intended.

Ok so my thaught processing here is that I have 6 LEDs that are defined by

int ledPins[] = {
 8, 9, 10, 11, 12, 13
  };                         // an array of pin numbers to which LEDs are attached

and then later setting them as outputs

for (int i = 0; i < pinCount; i++) {
    pinMode(ledPins[i], OUTPUT);      // use a for loop to initialize each pin as an output:
  }

In other words create an array of ledPins8, ledPins9, etc. and because arrays start at 0 my for loop needs to start at 0 (stet item 0 in the array as output = ledPins8 as output, item 1 = ledPins9, etc.).

and then I have an array that remembers the state of each Led

int LedState[]{ 
  0, 1, 2, 3, 4, 5          // state corresponding to each LED
  };

so LedState0 remembers the state of ledpins8. I also set all the LED states to LOW(Pins 8-13 not 0-5)

for (int i = 0; i < pinCount; i++) {
digitalWrite ( LedState[i], LOW);       // use a for loop to initialize all LED states LOW
  }

maybe it would help my code to read better if I also made my LedState 8-13. but it would make no difference because the value of 'i' in my for loops causes all the arrays to line up

for (int i = 0; i < pinCount; i++) { // apply LedState to corresponding LED OUTPUTS.
  digitalWrite(ledPins[i], LedState[i]);
  }

Take item 0-5 in LedState array and write their values to item 0-5 in ledPins array.

I hope all of that makes a little bit of sense and that it's not just a big old mess, this is basically my first Arduino project and I still have alot of coding etiquette to learn.

Clearly my code can be easily adapted to use an array.

That's (part of) why it uses pointers - those asterisk (*) thingies. :grinning:

@TO,
I was very unhappy with your non-consistent naming convention and usage of wrong camelCase in your variable names.

Nevertheless, the better starting point is the example Debounce from the Arduino IDE.

you used Pullups, so you will ground the button on press. Therefore you have to invers the reading result.

If you don't understand what your program is doing - add serial outputs and try to understand what's happening in your code. I tried to take over as much from your sketch as possible.

Putting these things together I end up with the debouncing example with arrays.

I don't have a test environment available, but it looks ok when I try to contact pins.
If you find any mis behavior, try to find the error - add more serial outputs or tell us what's wrong.

const int buttonPin[] = {  5, 3, 6,   2, 7,  4};     // Button Pins
const int ledPin[] =    {  8, 9, 10, 11, 12, 13};    // an array of pin numbers to which LEDs are attached
const int buttonCount = 6;
const int ledCount = 6;                              // the number of LEDs (i.e. the length of the array)

bool ledState[ledCount];                                     // state corrisponding to each LED
bool buttonState[buttonCount];                                  // readout of Button Pins
bool lastButtonState[buttonCount];                              // the previous reading from the input pin

unsigned long lastDebounceTime[buttonCount];  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  Serial.begin(115200);
  Serial.println(F("Serial output helps to understand the program logic"));

  // the array elements are numbered from 0 to (pinCount - 1)

  for (int i = 0; i < ledCount; i++) {
    pinMode(ledPin[i], OUTPUT);            // use a for loop to initialize each pin as an output:
  }
  for (int i = 0; i < buttonCount; i++) {
    pinMode(buttonPin[i], INPUT_PULLUP);       // use a for loop to initialize each pin as an input
  }
}

void loop() {

  for (byte i = 0; i < buttonCount; i++) {
    // read the state of the switch into a local variable:

    bool reading = !digitalRead (buttonPin[i]); // Read current button state for all buttonsin array.  // you have to invert!!!

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

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

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

      // if the button state has changed:
      if (reading != buttonState[i])
      {
        Serial.print(F("buttonPin[")); Serial.print(i); Serial.print(F("]=")); Serial.print(buttonPin[i]); Serial.print(F(" --> ")); Serial.println(reading);
        buttonState[i] = reading;

        // only toggle the LED if the new button state is HIGH
        if (buttonState[i] == HIGH) {
          ledState[i] = !ledState[i];
          // set the LED:
          digitalWrite(ledPin[i], ledState[i]);
          Serial.print(F("ledState[")); Serial.print(i); Serial.print(F("]=")); Serial.println(ledState[i]);
        }
      }
    }
    lastButtonState[i] = reading;
  }
}

I also set all the LED states to LOW(Pins 8-13 not 0-5)

No, you are in fact setting pins 0 to 5 to LOW:

for (int i = 0; i < pinCount; i++) {
  digitalWrite ( LedState[i], LOW);
}

If you want to set the states to LOW, do this:

for (int i = 0; i < pinCount; i++) {
  LedState[i] = LOW;
}

maybe it would help my code to read better if I also made my LedState 8-13.

That's no better. Each entry in LedState array should be HIGH or LOW, not a number like 3 or 11.

for (int i = 0; i < pinCount; i++) { // apply LedState to corresponding LED OUTPUTS.
  digitalWrite(ledPins[i], LedState[i]);
}

Yes, using the index variable i uses the elements for both arrays in-step. That's not the problem. Lets take i = 3 as an example:

digitalWrite(ledPins[i], LedState[i]);

becomes

digitalWrite(ledPins[3], LedState[3]);

which is

digitalWrite(11, 3);

But the second parameter of digitalWrite() should be HIGH or LOW, not 3.