Arduino multiple pushbuttons read

Hello, I just founded this community and I would be happy if I receive some help from more experienced :smile:

I have one problem. Lets say that I have 5 push buttons and 3 leds. Led1 turns on if at least 1 out of the 5 push buttons is pressed. Led2 turns on if at lest 3 push buttons are pressed and Led3 turns on if at least 4 push buttons are pressed. How can this be solved more efficient that what I already did ?

int led1 = 2;
int led2 = 3;
int led3 = 4;
int bp1 = 9; 
int bp2 = 8;
int bp3 = 7;
int bp4 = 6;
int bp5 = 5;

void setup()
 {
 Serial.begin(9600); 
 pinMode(led1, OUTPUT);
 pinMode(led2, OUTPUT);
 pinMode(led3, OUTPUT);
 pinMode(bp1, INPUT);
 pinMode(bp2, INPUT);
 pinMode(bp3, INPUT);
 pinMode(bp4, INPUT); 
 pinMode(bp5, INPUT);

}

void loop()

{

if (digitalRead(bp1)== HIGH or digitalRead(bp2)== HIGH or digitalRead(bp3)== HIGH or digitalRead(bp4)== HIGH or digitalRead(bp5)== HIGH )
{
  digitalWrite(led1, LOW);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
 }
else
{
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);

 }

if (digitalRead(bp1)== HIGH and digitalRead(bp4)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp4)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp2)== HIGH and digitalRead(bp4)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp3)== HIGH and digitalRead(bp4)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp4)== HIGH) 
    {
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, HIGH);
    }
else
  {
   digitalWrite(led1, HIGH);
   digitalWrite(led2, HIGH);
   digitalWrite(led3, HIGH);
   }

if (digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp4)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp4)== HIGH and digitalRead(bp5)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp4)== HIGH or digitalRead(bp1)== HIGH and digitalRead(bp2)== HIGH and digitalRead(bp3)== HIGH and digitalRead(bp5)== HIGH) 
   {digitalWrite(led1, HIGH);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW);
}

else
 {  digitalWrite(led1, HIGH);
   digitalWrite(led2, HIGH);
   digitalWrite(led3, HIGH);
   }


}

I have a couple of questions. Are these momentary pushbuttons that you have to hold down all at once, if for instance you want the condition to be 4 buttons pressed (are you debouncing the buttons)? In all cases, you don’t care which buttons are pressed, just how many, right?

Pending the answers to my questions, I’d say that you want to get the number of buttons that are pressed first, then use a switch statement to decide what outcome to produce. Something like this,

int numDown = digitalRead(bp1) + digitalRead(bp2) + digitalRead(bp3) + digitalRead(bp4) + digitalRead(bp5);
switch(numDown);
case 0:
    // respond to no buttons pressed;
    break;
case 1:
    //respond to 1 button pressed;
    break;
etc.
2 Likes

I am using a pushbutton that needs to be pressed and holded if I want to light a LED with it, so yes, these are momentary pushbuttons. With the code above everything works fine, I do not debouncing the buttons, I know a little about this how it can be done(hardware;using a capacitor or software;with debouncing code)

Exactly, order of the presses are not important, important is just that LED1 turns on when I press at least one pushbutton, it can be pushbutton nr.1 or pushbutton nr.5, order is not important. Same for LED2, not important which pushbuttons are pressed but there have to be at least 3 pushbuttons pressed at the same time. And for LED3, it will turns on minimum 4 pressed pushbuttons.

I got this code which at first sight looks ok but…it is not working for me :frowning:

// led pins
const byte led1 = 2;
const byte led2 = 3;
const byte led3 = 4;

// button input pins
const byte bp1 = 9;
const byte bp2 = 8; 
const byte bp3 = 7; 
const byte bp4 = 6; 
const byte bp5 = 5;


// array to hold the button read values
byte inputValues[5]; // 5 buttons

byte readingTotal;  //  holds sum of all button readings



void setup() 
{ 
  Serial.begin(9600);

  pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT);
  pinMode(bp1, INPUT); pinMode(bp2, INPUT); pinMode(bp3, INPUT);
  pinMode(bp4, INPUT); pinMode(bp5, INPUT);
}

void loop() 
{ 
 readButtons();   //  stores button read values in array
 readingTotal = addReadings();  //  store the sum of all button readings

 if (readingTotal == 1) {
  digitalWrite(led1, HIGH);
  digitalWrite(led2, LOW);  // make sure this led is off
  digitalWrite(led3, LOW);  // make sure this led is off
 } else if (readingTotal == 3) {
  digitalWrite(led1, HIGH);   // comment out if only one led at a time is desired
  digitalWrite(led2, HIGH);
  digitalWrite(led3, LOW);    // make sure this led is off
 } else if (readingTotal >= 4) {
  digitalWrite(led1, HIGH);   // comment out if only one led at a time is desired
  digitalWrite(led2, HIGH);   // comment out if only one led at a time is desired
  digitalWrite(led3, HIGH);
 } else {
  turnOffLEDS();  // make sure no leds are on if nothing is being pressed
 }
}

// read all the buttons and store values in array
void readButtons() {
  inputValues[0] = digitalRead(bp1);
  inputValues[1] = digitalRead(bp2);
  inputValues[2] = digitalRead(bp3);
  inputValues[3] = digitalRead(bp4);
  inputValues[4] = digitalRead(bp5);
}

// return total sum of button reads
byte addReadings() {
  byte readingSum = 0;

  return readingSum;
}

// turn off all leds
void turnOffLEDS() {
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
}

Here is my Proteus simulation of same case, using logical gates

Why don’t you try what I suggested, and see if it works for you. There’s no need for an array to hold the values, since you only need the total number pressed. Of course your code doesn’t work now, because the addReadings function only returns 0 as it is currently written.

2 Likes

One thing mechanical switches always need are pull-resistors to provide a logic level in open state.
The easiest would be pinMode(btnPin, INPUT_PULLDOWN) (assuming your buttons close to 3.3V - ***not 5V!***)
If they were closing to GND, you’d need INPUT_PULLUP and invert the readings for @Ric’s code to work as intended.
For 5V you’d need external pull-down resistors.

I’m not surprised your code doesn’t work. addReadings() will always return 0.

2 Likes

I tried with switch cases yesterday and I got stucked with the code and than went to sleep. But I will do it now because I want to understand it fully. About pulldown resistors I forgot to mention that I used them when I made this circuit on breadboard. I used 10k resistors, one per pushbutton, closing to GND(pull-down resistor). Like I said, breadboard circuit works ok with the code in first post, I was trying to see what are other options to solve this. And Ric one was good and will the one version with switch cases.

Scruffr or anyone else, what do you mean by ''addReadings() will always return 0 ‘’ ? What should I change in that code with arrays that it will function ?

For now, my best and simplest solution is this;

int buttonCounter = 0; //reset after each cycle

if (digitalRead (bp1) == HIGH){buttonCounter++;}
if (digitalRead (bp2) == HIGH){buttonCounter++;}
if (digitalRead (bp3) == HIGH){buttonCounter++;}
if (digitalRead (bp4) == HIGH){buttonCounter++;}
if (digitalRead (bp5) == HIGH){buttonCounter++;}  


if(buttonCounter > 0){digitalWrite(led1, LOW);}
if(buttonCounter >= 3){digitalWrite(led2, LOW);}
if(buttonCounter >= 4){digitalWrite(led3, LOW);}

else
{ 
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
}

If your buttons are closing to GND you need pull-up resistors to provide the opposite level when not closed.

How could I mean that any other way than literally looking at this code of yours?

byte addReadings() {
  byte readingSum = 0;

  return readingSum;
}

Now I connected LCD display to show which buttons is pressed and now with lcd display code included I have problem that leds are not bright enough if I (with push buttons combinations) light on led1 or led2. But if I press 4 or 5 buttons at the same time, all leds turn on at full force. Quite bizzare

Not really bizzare, it’s what you told the code to do

if(buttonCounter > 0) {
  digitalWrite(led1, LOW);
}

if(buttonCounter >= 3) {
  digitalWrite(led2, LOW);
}

if(buttonCounter >= 4) {
  digitalWrite(led3, LOW);
}
else { 
  digitalWrite(led1, HIGH);
  digitalWrite(led2, HIGH);
  digitalWrite(led3, HIGH);
}

I have just reformatted your code, but not altered the logic - does this make things clearer?

When buttonCounter is not greater or equal 4, led1 & led2 will only stay on for a few clock cycles before the else branch switches them off again :wink:

I’d rewrite your code like this

  buttonCount = digitalRead(bp1) 
              + digitalRead(bp2)
              + digitalRead(bp3)
              + digitalRead(bp4)
              + digitalRead(bp5);

  digitalWrite(led1, !(buttonCount >= 1));
  digitalWrite(led2, !(buttonCount >= 3));
  digitalWrite(led3, !(buttonCount >= 4));

or actually I’d even go for


// led pins
const byte leds[] = { 2, 3, 4 };       // for Particle devices don't use these anonymous pin numbers!
const int  ledsCount = sizeof(leds);   // keep things dynamic

// button input pins
const byte bp[] = { 9, 8, 7, 6, 5 };   // for Particle devices don't use these anonymous pin numbers!
const int  bpCount = sizeof(bp);       // keep things dynamic
...

void loop() {
  int buttonCounter = 0;
  for (int i = 0; i < bpCount; i++)
    buttonCount += digitalRead(bp[i]));

  digitalWrite(led[0], !(buttonCount >= 1));
  digitalWrite(led[1], !(buttonCount >= 3));
  digitalWrite(led[2], !(buttonCount >= 4));
}

But just to say, there is no pin number 9 on a Particle device, so I guess you are not quite correct in the Particle community asking Arduino questions :sunglasses:

Thank you for answers but that thing I understand how it works. Like I wrote, my problem is that AFTER I added code for LCD display(which works ok), when LED1 and LED2 turn on with push button presses(accordingly by written logic), these 2 Leds are quite dimmed; they do not have same brightness as they do if I put the code for LCD in //. And this is what I do not undestand…how the code for LCD display intefere with the LEDs…I have 2 breadboards, one for pushbuttons and LEDs and one for LCD display.

What is written on display is just an example text(in void setup function), but If I put the code in void loop function, than when I turn on, for exemple, the LED1, it turns on but it is very dimmed, like that there is not enough power for LED1 or something…If I exclude the code for LCD, than when I press, for exemple, push button1, LED1 turns on with full brightness…Surprisingly, if I press 4 push buttons, they all light up with full brightness, it is just that if I turn on LED1 or LED2, they light up dimmed, I can barely see that they are ON.

I have already expained why led 1 & 2 are dim when 3 is not lit.

The LCD code will influence the timing of your loop() and hence the timing of the ON/OFF cycles of your LEDs.

1 Like

But why is this only happening when LCD code is added ? Because led1 and led2 are not dimmed if I exclude lcd code…

Ok, thank you very much for all the answers and clarification.