Sunday, March 18, 2012

R2R Button Resistor Ladder

I'm sure everyone has encountered that time when you use all your digital ports for other things, but then you also need a button. It is possible to use a analog port as a digital port (pinMode(A0,Input/Output);), or you can use a few resistors and have a whole bunch of buttons(4+ easily) on one analog port.

Basically, this is how it works: A 10k resistor pulls the analog pin low, then each button is connected to the analog pin, and a resistor of some value to Vcc on the button. Each buttons resistor value is different so that Arduino can tell which button has been pressed. I found it best to use odd values values starting at 300ohm. Ex 300ohm, 500, 700, ..., 1.1k, 1.3. That way, if two buttons are pressed at once the resulting value is different than any of the buttons being pressed individually. Or you could use 1k, 3k, 5k... etc. The main thing is to make sure two buttons don't equal another button when pressed.

Made with Fritzing
Code:

#define  AnalogBtnPin A0
int AnalogBtn =0;
int Button1Cnt =0;
int Button2Cnt =0;
int Button3Cnt =0;
int Button4Cnt =0;
int Button5Cnt =0;
void setup()
{
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
   AnalogBtn = analogRead(AnalogBtnPin);
  Serial.println( AnalogBtn);

  if(AnalogBtn >= 508 &&  AnalogBtn <= 510)
  {
    Button1Cnt +=1;
    Serial.print("Button 1 pressed ");  Serial.print(Button1Cnt);  Serial.println(" times.");
  }

  if(AnalogBtn >= 888 &&  AnalogBtn <= 890)
  {
    Button2Cnt +=1;
    Serial.print("Button 2 pressed ");  Serial.print(Button2Cnt);  Serial.println(" times.");
  }

  if(AnalogBtn >= 970 &&  AnalogBtn <= 972)
  {
    Button3Cnt +=1;
    Serial.print("Button 3 pressed ");  Serial.print(Button3Cnt);  Serial.println(" times.");
  }

  if(AnalogBtn >= 1003 &&  AnalogBtn <= 1005)
  {
    Button4Cnt +=1;
    Serial.print("Button 4 pressed ");  Serial.print(Button4Cnt);  Serial.println(" times.");
  }

  if(AnalogBtn >= 1014 &&  AnalogBtn <= 1016)
  {
    Button5Cnt +=1;
    Serial.print("Button 5 pressed ");  Serial.print(Button5Cnt);  Serial.println(" times.");
  }
}

Note: you will have to find the correct thresholds for your resistors.

6 comments:

  1. Nice :)

    You can also enhance the readings accuracy using some software debouncing + "value sampling".

    ie : when pressing button (if enough time has elapsed after button is clicked), read the input for X times, and add each reading to an accumulator.
    Then, to get the final read value, divide the accumulator value by X. That way, you get an average value that will even any difference from successive readings.

    For X, you can use any value, but powers of 2 are better (say 16, 32,64, etc) 'cause the compiler can optimize it with a shift instruction (which is faster).

    ReplyDelete
  2. yeah, thats a good idea. basically something like this:

    for(int i =0; i<5; i++)
    {
    AnalogBtn = 0;
    AnalogBtn += analogRead(AnalogBtnPin);
    }

    AnalogBtn = AnalogBtn/5

    for anyone who wants it

    ReplyDelete
  3. how do u calculate the analog values? i mean the "(AnalogBtn >= 508 && AnalogBtn <= 510)" for example, how do u get that number?

    ReplyDelete
    Replies
    1. run the sketch and hold down the button you want to find the value of now it should be printing to the serial terminal in the arduino IDE. but the value wont always be the exact same thing. it may be off a number or two, so take the value and think of a range so if the serial termianl says 505, your min would be 500, the max would be 510.

      if(AnalogBtn >= 500 && AnalogBtn <= 510)
      {
      Button1Cnt +=1;
      Serial.print("Button 1 pressed "); Serial.print(Button1Cnt); Serial.println(" times.");
      }

      Delete
  4. As an admitted noob, you just solved my design quandary. Kudos to you.

    ReplyDelete