Unusual readings trying to use multiple buttons on one analog pin.

As the title implies, I am trying to use multiple buttons on 1 analog pin to conserve i/o pins on my arduino. I tried to make an example in Fritzing but confused myself, so I took a detailed picture that I will try to explain.

I bought a 4 button membrane from adafruit, and am using it to control my arduino project. I want to hook all 4 buttons to 1 analog pin, using resistors. I'm under the impression that I can affect the value when I read the analog input to determine which button it is. My current set up seems to work, but not as intended, but I can't figure out exactly what I did wrong. I'm almost confident that it has to do with how I wired it up.

This picture shows my set up (only be concerned with rows 1-5). Row 1 is the common ground for all 4 buttons, The 3 vertical resistors are 2.2k and used to change the analog value. The horizontal resistor is a 2.2k acting as a pull up (at least that's what i want it to be). The yellow jumper, which is plugged in row 5, goes to A5 on the Arduino.

Here is the output of reading the analog pin when I press the buttons. ~671 is the no button reading, ~445 is button one, ~501 is button two, ~3 is button three, and ~333 is button four. While I could probably use these reading to make this work, I feel like its supposed to be between 0 and 1023.

Is what I am doing correct, or do I need to adjust something?

(p.s. if this is the wrong section, sorry ahead of time, was debating between here and 'General Electronics')

Post your code too

Oh sorry, overlooked that bit.

Extremely simple sketch.

You can imbed small sketches in your post, inside code tags. Here it is:

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

void loop() {
  Serial.println(analogRead(A5));
  delay(200);
}

Your output:

671
671
671
671
671
671
671
671
671
670
670
670
671
670
671
670
671
670
445
446
445
445
670
671
670
501
501
502
670
670
671
670
671
671
3
2
2
3
671
333
333
333
333
333
670
670
671
670
670
670
670
670
671
671
670
671
670
670
670
671
671
671
671
671
671
670
671
671

Not everyone wants to go to off-site places to download code.

I feel like its supposed to be between 0 and 1023.

It is, as far as I can see.

[quote author=Nick Gammon link=topic=186157.msg1378505#msg1378505 date=1378262548]

I feel like its supposed to be between 0 and 1023.

It is, as far as I can see.
[/quote]More specifically, I thought that the no button value should be closer to 1023. When I get 3, it seems wrong but I am not sure why. It doesnt seem to match a pattern with the rest of the values as I would expect.

If you press row 5 which grounds it, you would expect around 0V wouldn't you?

[quote author=Nick Gammon link=topic=186157.msg1378512#msg1378512 date=1378263177]
If you press row 5 which grounds it, you would expect around 0V wouldn't you?
[/quote]Ah, I guess that does make sense. I guess my last question would be, do I need a pull up resistor when I am using an analog pin?

What you have there looks right to me, but I can't really explain the figures. I can get:

5V --- 2.2K --- A5 --- 2.2K --- Gnd

Ok that should be 512 which is close to your 501.

And:

5V --- 2.2K --- A5 --- 4.4K --- Gnd

That should be 682 which is close to your 671.

But:

5V --- 2.2K --- A5 --- 6.6K --- Gnd

Should be 767, so I don't see where 333 comes from. Unless you have the pins around the wrong way.

Alright Nick, I am confused now. I have the exact same setup, and I am trying to apply the new system to my previous code (where all the buttons were digital pins). Why would the values of analogRead(A5) be different now? If I upload my previous test sketch, they change back to the original values...

846
846
847
847
847
847
846
847
560
560
560
560
560
560
560
560
560
561
847
847
846
845
847
632
632
632
631
632
632
632
632
632
846
847
847
846
848
847
4
4
4
4
4
4
4
4
5
846
847
845
846
847
419
419
419
419
419
419
419
419
419

Here is the sketch I am implementing this in,

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
//button reference
int button = 0;

int rotations = 0; //track wheel rotations for averaging

int screen = 5; //value to differenciate screens in switch statement

unsigned long curMils = 0; //current milliseconds
unsigned long prevMils = 0; //previously stored milliseconds

double fastestMph = 0;
double mph = 0;
double dist = 0;

//values for tracking average speed
double mphTotal = 0;
double mphAvg = 0;

boolean checked = false; //prevents multiple calcultions when the reed closes
boolean reset = false; //prevents multiple mph resets after a delay

void setup() {
  Serial.begin(9600);
  //print splash screen
  lcd.begin(16, 2);
  lcd.print("Mason's     v0.1");
  lcd.setCursor(3,1);
  lcd.print("Bike Computer");
  
  //set reed switch pin to input
  pinMode(8, INPUT);
}

void loop() {
  button = analogRead(A5);
  Serial.println(button);
  delay(100);
  //reset distance traveled or average speed if button 4 is pressed
  if (button == 2 || button == 3) {
    switch(screen) {
      case 0:
        mphTotal = 0;
        rotations = 0;
        break;
      case 1:
        fastestMph = 0;
        lcd.setCursor(7,1);
        lcd.print("         ");
        lcd.setCursor(7,1);
        lcd.print(fastestMph);
        lcd.print("mph");
        break;
      case 2:
        dist = 0.00;
        lcd.setCursor(7,1);
        lcd.print(dist);
        lcd.print("mi");
        break;
    }
  }
  //change screen value if button is pressed
  if (button == 445 || button == 446) {
    //change screen 
    if (screen == 2) screen = 0;
    else screen++;
    
    //display proper screen on lcd
    switch (screen) {
      case 0:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("MPH: ");
        lcd.setCursor(5,0);
        lcd.print("      ");
        lcd.setCursor(5,0);
        lcd.print(mph);
        lcd.setCursor(0,1);
        lcd.print("Avg: ");
        lcd.print("      ");
        lcd.setCursor(5,1);
        lcd.print(mphAvg);
        break;
      case 1:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Fastest MPH: ");
        lcd.setCursor(7,1);
        lcd.print(fastestMph);
        lcd.print("mph");
        break;
      break;
      case 2:
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Total Distance: ");
        lcd.setCursor(7,1);
        lcd.print(dist);
        lcd.print("mi");
        break;
    }
    delay(250);
  }
      
  //do calculations when the reed closes
  if (digitalRead(8) == LOW && !checked) {
    //keep track of rotations of wheel
    rotations++;
    
    //calculate current mph 
    curMils = millis();
    mph = (4873.591953413029) / (curMils - prevMils);
    prevMils = curMils;
    
    //calculate distance traveled
    dist = dist + 0.000430921;
    
    //calculate the average speed
    mphTotal = mphTotal + mph;
    mphAvg = mphTotal / rotations;
    
    //calculate fastest mph
    if (mph > fastestMph) {
      fastestMph = mph;
    }
    
    //mark that calculations have occured for this rotation
    checked = true;
    reset = false;
    
    //display output to lcd
    switch(screen) {
      case 0:
        lcd.setCursor(5,0);
        lcd.print("      ");
        lcd.setCursor(5,0);
        lcd.print(mph);
        lcd.setCursor(5,1);
        lcd.print("      ");
        lcd.setCursor(5,1);
        lcd.print(mphAvg);
        break;
      case 1:
        lcd.setCursor(7,1);
        lcd.print(fastestMph);
        lcd.print("mph");
        break;
      case 2:
        lcd.setCursor(7,1);
        lcd.print(dist);
        lcd.print("mi");
        break;
      default:
        lcd.print("Mason's     v0.1");
        lcd.setCursor(3,1);
        lcd.print("Bike Computer");
        break;
    }
  }
  if (digitalRead(8) == HIGH && checked) {
    checked = false;
  }
  if ((millis() - prevMils) >= 2500 && !reset) {
    mph = 0;
    if (screen == 0) {
      lcd.setCursor(5,0);
      lcd.print("      ");
      lcd.setCursor(5,0);
      lcd.print(mph);
    }
    reset = true;
  }
  
}

Don't know for sure. Get your meter out and read the voltage on A5 with each switch pressed and see if it is what you expect. Also check the 5V pin. Maybe the screen is drawing a lot of current.

I am using this exact same system, you never get 1023, unless you have a resistor directly connected between the 5 volt rail and your analog input, and no other resistor connected to earth.

You want a voltage divider system with your buttons earthing it at different points.

I am using 1k resistors in my system, with 5 buttons.

Shows you the resistor and button system on the freetronics shield, which does return 1023 until you push a button.

I am using 1k resistors in my system, with 5 buttons, i just extended the resistor chain a little bit.

Here is my code, ignore the Ktimer part, as its part of the automatic repeat/delay system.

ButtonWindow is defined to be 10, as the analog values can jump around a little bit, so you need to have a bit of leeway for noise.

OldButton=Button;
Keypress=analogRead(1);
if (Keypress>1024-ButtonWindow){
Button = 0; // nothing pressed, all keys released.
// reset the keypress timer
Ktimer=0;
Kthresh=Krepeat; //reset it
Kaccel=Kthresh/2;
}
if ((Keypress>=768-ButtonWindow)&&(Keypress<=768+ButtonWindow)) {
Button=K_R;
Ktimer=Ktimer+1;
}
if ((Keypress>=683-ButtonWindow)&&(Keypress<=683+ButtonWindow)) {
Button=K_U;
Ktimer=Ktimer+1;
}
if ((Keypress>=819-ButtonWindow)&&(Keypress<=819+ButtonWindow)) {
Button=K_D;
Ktimer=Ktimer+1;
}

if ((Keypress>=511-ButtonWindow)&&(Keypress<=511+ButtonWindow)) {
Button=K_L;
Ktimer=Ktimer+1;
}

if (Keypress<=ButtonWindow) {
Button=K_S;
Ktimer=Ktimer+1;
}

Jeebis, can you draw a circuit diagram?
Your values shouldnt change just because of a change in the sketch, unless you are referencing the ADC to something else.

Sorry for it being a little cluttered, but this is my current breadboard set up. The four buttons represent the 4 button membrane I bought form adafruit, as there was no object for that. The screen is a QC1602A and the trim pot is a small 10k one.

[quote author=Nick Gammon link=topic=186157.msg1378580#msg1378580 date=1378270389]
Don't know for sure. Get your meter out and read the voltage on A5 with each switch pressed and see if it is what you expect. Also check the 5V pin. Maybe the screen is drawing a lot of current.
[/quote]So I just measured the voltages and noticed something weird... When I check the voltage from ground to the 3.3v pin, I get an expected ~3.26v, but when I check on the positive side of my breadboard, I have ~4.1v... When I push the small test sketch I was using to find the analog values, it goes back to ~3.26v. So the values are changing because the voltage reference is changing. Any idea what would cause this to happen?

Change that red wire going to the buttons, a resistor. This way you will have a voltage divider and not just a current divider.

I don't see anything connecting that bottom red rail to 5V power.

[quote author=Nick Gammon link=topic=186157.msg1379584#msg1379584 date=1378328648]
I don't see anything connecting that bottom red rail to 5V power.
[/quote]Whoops, looks like I neglected that wire on the diagram. Both sets of rails are connected on my project.

HazardsMind:
Change that red wire going to the buttons, a resistor. This way you will have a voltage divider and not just a current divider.

What would be better about having a voltage divider in this case?