Go Down

Topic: Multiple Buttons on 1 analog pin (Read 71185 times) previous topic - next topic

digimike

Thought i'd share a little project i've been working on. As many may know there is a method for using a single analog pin to control multiple buttons. There is even a library for it. Problem is the way they connect the circuit doesn't allow for the use of button combinations.



So you couldn't press 2 buttons at the same time to perform a different action.

Rather then connecting the resistors in series like that i reorganized it in parallel.



Then i sorted the buttons into a directional pad configuration with 2 action buttons.



Trick was working out which resistors to use on the buttons. If the resistor values are not right then the values read by the analog pin could be too close or overlap on some combos. So here are the possible 2 button combos and values the analog pin will see when the buttons are pressed.

Quote

BUTTONS        VALUES     RESISTORS
btn 1                 837-838    220
btn 2                 737-738    390
btn 3                 610-611    680
btn 4                 318-319    2.2k
btn 5              178-179    4.7k
btn 6                 91-92        10k
btn 1 + btn 2   896-897      
btn 1 + btn 3   877-878      
btn 1 + btn 4   851-852      
btn 1 + btn 5   844-845      
btn 1 + btn 6   840-841      
btn 2 + btn 3   821-822      
btn 2 + btn 4   769-770      
btn 2 + btn 5   753-754      
btn 2 + btn 6   745-746      
btn 3 + btn 4   674-675      
btn 3 + btn 5   643-644      
btn 3 + btn 6   627      
btn 4 + btn 5   408-409      
btn 4 + btn 6   363-364      
btn 5 + btn 6   243


Here is the code i put together for using the buttons in this controller configuration.
Code: [Select]
/*
AnalogButton_Combos
Version 0.1

Connection more then one button to a single analog pin. Utilizing
software debounce to prevent registering multiple button press
while allow for 2 button combos to be registered.  

The Circuit:
 Most other analog buttons circuits call for the resistors to be
 lined up in series from ground. The analog pin and each button
 connect off one of the resistors. My cuicuit requires that the
 resistors tie in from +5 to the buttons. The buttons all connect
 to the analog pin which is tied to ground threw a 1k resistor as
 seen in the diagram below.

        Analog pin 5
           |
Ground--1K--|--------|--------|-------|-------|
           |        |        |       |       |
          btn1     btn2     btn3    btn4    btn5
           |        |        |       |       |
        220 Ohm  390 Ohm  680 Ohm   2.2K    4.7K
           |--------|--------|-------|-------|-- +5V
           
Created By: Michael Pilcher
February 24, 2010

*/
int j = 1; // integer used in scanning the array designating column number
//2-dimensional array for asigning the buttons and there high and low values
int Button[21][3] = {{1, 837, 838}, // button 1
                    {2, 737, 738}, // button 2
                    {3, 610, 611}, // button 3
                    {4, 318, 319}, // button 4
                    {5, 178, 179}, // button 5
                    {6, 91, 92}, // button 6
                    {7, 896, 897}, // button 1 + button 2
                    {8, 877, 878}, // button 1 + button 3
                    {9, 851, 852}, // button 1 + button 4
                    {10, 844, 845}, // button 1 + button 5
                    {11, 840, 841}, // button 1 + button 6
                    {12, 821, 822}, // button 2 + button 3
                    {13, 769, 770}, // button 2 + button 4
                    {14, 753, 754}, // button 2 + button 5
                    {15, 745, 746}, // button 2 + button 6
                    {16, 674, 675}, // button 3 + button 4
                    {17, 643, 644}, // button 3 + button 5
                    {18, 627, 627}, // button 3 + button 6
                    {19, 408, 409}, // button 4 + button 5
                    {20, 363, 364}, // button 4 + button 6
                    {21, 243, 243}}; // button 5 + button 6
int analogpin = 5; // analog pin to read the buttons
int label = 0;  // for reporting the button label
int counter = 0; // how many times we have seen new value
long time = 0;  // the last time the output pin was sampled
int debounce_count = 50; // number of millis/samples to consider before declaring a debounced input
int current_state = 0;  // the debounced input value
int ButtonVal;

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

}

void loop()
{
  // If we have gone on to the next millisecond
 if (millis() != time)
 {
   // check analog pin for the button value and save it to ButtonVal
   ButtonVal = analogRead(analogpin);
   if(ButtonVal == current_state && counter >0)
   {
     counter--;
   }
   if(ButtonVal != current_state)
   {
     counter++;
   }
   // If ButtonVal has shown the same value for long enough let's switch it
   if (counter >= debounce_count)
   {
     counter = 0;
     current_state = ButtonVal;
     //Checks which button or button combo has been pressed
     if (ButtonVal > 0)
     {
       ButtonCheck();
     }
   }
   time = millis();
 }
}

void ButtonCheck()
{
 // loop for scanning the button array.
 for(int i = 0; i <= 21; i++)
 {
   // checks the ButtonVal against the high and low vales in the array
   if(ButtonVal >= Button[i][j] && ButtonVal <= Button[i][j+1])
   {
     // stores the button number to a variable
     label = Button[i][0];
     Action();      
   }
 }
}

void Action()
{
 if(label == 1)
 {
   Serial.println("Up Button");
 }
 if(label == 2)
 {
   Serial.println("Down Button");
 }
 if(label == 3)
 {
   Serial.println("Left Button");
 }
 if(label == 4)
 {
   Serial.println("Right Button");
 }
 if(label == 5)
 {
   Serial.println("Action Button #1");
 }
 if(label == 6)
 {
   Serial.println("Action Button #2");
 }
 if(label == 8)
 {
   Serial.println("Left and Up Buttons");
 }
 if(label == 9)
 {
   Serial.println("Right and Up Buttons");
 }
 if(label == 12)
 {
   Serial.println("Left and Down Buttons");
 }
 if(label == 13)
 {
   Serial.println("Right and Down Buttons");
 }
 if(label == 21)
 {
   Serial.println("Action Buttons #1 and #2");
 }    
     
 //Serial.println("Button =:");
 //Serial.println(label);
 //delay(200);
 
 
}




Next i will be working on a nice 12 button keypad using this method. Sure you can get a 12 button keypad now but you'll be using row and column scanning to detect the buttons which takes up 7 digital I/O pins. With this analog button method i can have a 12 button keypad that only needs +5, Ground and a single analog pin. And this keypad will be able to accept button combinations. Hard part will be working out the best resistor values for it, the possible button combos and analog values. Not that a keypad would have much use for combos but it will be there. Besides the pad could always be used as a directional pad too.

srylul

#1
Feb 25, 2010, 06:45 pm Last Edit: Feb 25, 2010, 06:46 pm by srylul Reason: 1
Easy as a falling apple!
When somebody tells me how something works or can be done, I try to remember how big the universum is compared to me...
Good work. I will use your idea in a later project.

udoklein

I had such a setup as well. Some of the LCD shields do this. The issue is: it is not really 100%, especially if your voltage varies or your resistors vary (e.g. due to temperature changes). Last summer it started to fail during some very hot days.

--> I would stick to read the pins digitally. If necessary using a shift register.

Cheers, Udo
Check out my experiments http://blog.blinkenlight.net

frostin

Thanks for this :). I'll be using buttons on my rgb lamp whenever all parts come in.

digimike

Very true. Power supply instability and temperature changes can effect the readings. This is why i tried to get resistor values so that the received value on the analog pins had a good separation to them. Then you won't get any button overlaps do to the possible instability. So i suggest when using this to verify the resistor readings before implementing this. Fortunately if your using USB power from your PC its going to be pretty stable. Room temp is a different story.

But if the resistor values have a good separation then you should be able to adjust the high and love values for the buttons to compensate for any variation.


digimike

#5
Feb 26, 2010, 06:57 pm Last Edit: Feb 26, 2010, 08:29 pm by digimike Reason: 1
Made some changes to the code and incorporated an LCD. Basically the code now moves the cursor around the LCD screen. Now with the LCD connected the code worked fine. Then when i turned on the back light it became such a drain on the power that the buttons didn't work. So i went and changed the values to compensate for this.

I also did testing using a battery pack of 4 AAA batteries and a 9V battery. It all works perfectly well. Though the batteries are relatively new.

Now the values for button 1 + button 5 and button 1 + button 6 overlap. But thats not a problem in this configuration. We are only using  buttons 1, 2, 3, 4, 5, 6, 1+3, 1+4, 2+3, and 2+4. Buttons 5 and 6 havn't been assigned to do anything yet.

Code: [Select]
/*
AnalogButton_Combos
Version 0.1

Connection more then one button to a single analog pin. Utilizing
software debounce to prevent registering multiple button press
while allow for 2 button combos to be registered.  

The Circuit:
 Most other analog buttons circuits call for the resistors to be
 lined up in series from ground. The analog pin and each button
 connect off one of the resistors. My cuicuit requires that the
 resistors tie in from +5 to the buttons. The buttons all connect
 to the analog pin which is tied to ground threw a 1k resistor as
 seen in the diagram below.

        Analog pin 5
           |
Ground--1K--|--------|--------|-------|-------|
           |        |        |       |       |
          btn1     btn2     btn3    btn4    btn5
           |        |        |       |       |
        220 Ohm  390 Ohm  680 Ohm   2.2K    4.7K
           |--------|--------|-------|-------|-- +5V
           
For this code you want to arrange the buttons in a d pad
cofiguration and 2 action buttons. btn1 up, btn 2 down,
btn3 left, btn4 right, btn 6 A, btn 7 B.
           
Created By: Michael Pilcher
February 24, 2010

*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

int j = 1; // integer used in scanning the array designating column number
//2-dimensional array for asigning the buttons and there high and low values
int Button[21][3] = {{1, 834, 838}, // button 1  *up
                    {2, 734, 738}, // button 2  *down
                    {3, 604, 611}, // button 3  *left
                    {4, 314, 319}, // button 4  *right
                    {5, 174, 179}, // button 5  *A
                    {6, 87, 92}, // button 6    *B
                    {7, 892, 897}, // button 1 + button 2
                    {8, 870, 878}, // button 1 + button 3
                    {9, 847, 852}, // button 1 + button 4
                    {10, 840, 845}, // button 1 + button 5
                    {11, 836, 841}, // button 1 + button 6
                    {12, 815, 822}, // button 2 + button 3
                    {13, 765, 770}, // button 2 + button 4
                    {14, 749, 754}, // button 2 + button 5
                    {15, 741, 746}, // button 2 + button 6
                    {16, 670, 675}, // button 3 + button 4
                    {17, 639, 644}, // button 3 + button 5
                    {18, 623, 627}, // button 3 + button 6
                    {19, 404, 409}, // button 4 + button 5
                    {20, 359, 364}, // button 4 + button 6
                    {21, 239, 243}}; // button 5 + button 6
int analogpin = 5; // analog pin to read the buttons
int label = 0;  // for reporting the button label
int counter = 0; // how many times we have seen new value
long time = 0;  // the last time the output pin was sampled
int debounce_count = 50; // number of millis/samples to consider before declaring a debounced input
int current_state = 0;  // the debounced input value
int ButtonVal;
int x = 0;
int y = 0;

void setup()
{
 lcd.begin(16, 2);
 lcd.setCursor(x,y);
 lcd.write(255);
}

void loop()
{
  // If we have gone on to the next millisecond
 if (millis() != time)
 {
   // check analog pin for the button value and save it to ButtonVal
   ButtonVal = analogRead(analogpin);
   if(ButtonVal == current_state && counter >0)
   {
     counter--;
   }
   if(ButtonVal != current_state)
   {
     counter++;
   }
   // If ButtonVal has shown the same value for long enough let's switch it
   if (counter >= debounce_count)
   {
     counter = 0;
     current_state = ButtonVal;
     //Checks which button or button combo has been pressed
     if (ButtonVal > 0)
     {
       ButtonCheck();
     }
   }
   time = millis();
 }
}

void ButtonCheck()
{
 // loop for scanning the button array.
 for(int i = 0; i <= 21; i++)
 {
   // checks the ButtonVal against the high and low vales in the array
   if(ButtonVal >= Button[i][j] && ButtonVal <= Button[i][j+1])
   {
     // stores the button number to a variable
     label = Button[i][0];
     Action();      
   }
 }
}

void Action()
{
 // mover cursor up
 if(label == 1 && y > 0)
 {
   y = y - 1;
 }
 // move cursor down
 if(label == 2 && y < 1)
 {
   y = y + 1;
 }
 // move cursor left
 if(label == 3 && x > 0)
 {
   x = x - 1;
 }
 // move cursor right
 if(label == 4 && x < 15)
 {
   x = x + 1;
 }
 
 if(label == 5)
 {
   // action button A
 }

 if(label == 6)
 {
   // action button B
 }
 // move cursor left and up
 if(label == 8 && x > 0 && y > 0)
 {
   x = x - 1;
   y = y - 1;
 }
 // move cursor right and up
 if(label == 9 && x < 15 && y > 0)
 {
   x = x + 1;
   y = y - 1;
 }
 // move cursor left and down
 if(label == 12 && x > 0 && y < 1)
 {
   x = x - 1;
   y = y + 1;
 }
 // move cursor right and down
 if(label == 13 && x < 15 && y < 1)
 {
   x = x + 1;
   y = y + 1;
 }
 
 if(label == 21)
 {
   // action button A + Bk
 }
 else
 {
   lcd.clear();
   lcd.setCursor(x, y);
   lcd.write(255);
 }  
}



Major25

thank you so much for the diagram, I saw another wiring diagram to accomplish something similar but it was much more difficult to read, this was perfect and got multiple buttons on one analog pin going for me in minutes, thank you!

jdoll

To unambiguously decode multiple, simultaneous buttons, binary weighting for the button values seems like the way to go.  This can be done by connecting the buttons to an R-2R ladder network.  There is a good article on this at http://en.wikipedia.org/wiki/R-2R_ladder#R-2R_resistor_ladder_network.

If all resistors and the reference were perfect, best possible resolution would be 10 buttons - one for each bit of ADC converter accuracy.  In practice, 8 buttons may be readable in any combination if the ladder is constructed from 0.1% precision resistors.

mpeuser

Don't mind the nominal precision. Just buy a charge of any equal resistors.... They will be equal...

(I think this concept has been discussed three times during the last month :-) )

inizul

#9
Oct 03, 2010, 09:49 pm Last Edit: Oct 03, 2010, 09:50 pm by inizul Reason: 1
Hi all

You may be interested in the following pages:

multiple buttons in an analog input
http://txapuzas.blogspot.com/2010/07/papertecladoanalogico-varios-pulsadores.html

Multiple buttons on a digital input
http://txapuzas.blogspot.com/2010/09/papertecladorc-varios-pulsadores.html

(The pages are in Spanish, but have plenty of pictures and have a machine translator in the top right of the page)

madepablo

Great tutorial! Thanks for share it with us.

I would like to apply this idea but only for 4 buttons. I suppose that you made multiple experiments, so may be you could propose to me what resistances to use. Any idea or proposal?

Thanks!

REBinc

#11
Nov 12, 2010, 11:59 pm Last Edit: Nov 13, 2010, 12:00 am by REBinc Reason: 1
I have something similar to this hooked up in my car, the OEM steering wheel controls are 8 buttons with different resistance values associate with each, all going through the clockspring on 1 wire. However, like stated above, the voltage variance make some of them hard to distinguish depending on what accessories are running in my car. What I did was take the null button resistance value, and I scale my readings to that continuously, so any fluctuations are accounted for.

madepablo

#12
Nov 22, 2010, 09:19 pm Last Edit: Nov 22, 2010, 09:22 pm by madepablo Reason: 1
Thanks!

I tried the faster option... to try the same circuit except the last button and the last resistance to have 4 buttons configuration. And it runs!!!

FYI, here are the values (minimum and maximum) from reading the analog pin, when using different buttons and combinations:
Quote

button     min.       max.
1      839      840
2      736      738
3      608      609
4      316      317
1 2      897      899
1 2 3      916      918
1 2 3 4      921      923
1 2 4      903      905
1 3       877      879
1 3 4      886      888
1 4      853      854
2 3      820      821
2 3 4      837      838
2 4      768      770
3 4      672      674


Just only to combinations results dangerously near:
button 1 and buttons 2+3+4
But if you don´t use this combination in you program setting, it should not be a problem.

I hope it could be useful for your projects.

Cheers,

Go Up