
Sometimes you just need one more input button or switch.
There are many different ways to use you existing pins more efficiently. If you still have a free analog pin, you could use a resistor ladder to connect multiple buttons to one pin. Or you could use a key matrix to drastically cut you pin count for many buttons. However, if you only need one or two additional pins, here is a neat way to connect 1.5 buttons per input pin.
In programing, we normally think purely binary. A button is either pressed or not, a bit is either 1 or 0. However even in digital electronics, there is often a third option: Unconnected or floating. With one external resistors and the internal pull-up resistor available in most microcontrollers, we can actually read all three states from an input pin.
The trick is to connect an external pull-down resistor with a much larger resistance than the internal pull-up resistor.
When we read the input , we first check if the input is high or low, without the internal pull-up activated. If the pin is high, that can only mean, that U1 is pressed. If the pin is low, it is either pulled down by R1, or by U2. We can now activate the internal pull-up resistor. Since this resistor is usually around 10k – 40k, it would pull the input notably higher, if U2 is not pressed. If U2 is pressed, the input will stay low.
R2 is optional, but it will prevent a short, if both buttons are pressed at the same time.
Here is a small arduino sketch as an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
/* Ternary Input Example This example demonstrates, how to read 3 different inputs (low, high, not connected) with a single digital pin. The circuit: * Momentary switch from pin 2 to V+ * Momentary switch from pin 2 to 120 - 1k Ohm resistor to GND * 200k - 1M resistor from pin 2 to GND created 23 March 2013 by Philip Peter This example code is in the public domain http://www.justgeek.de/using-internal-pull-ups-to-read-tri-state-inputs */ #define BUTTON_PIN 2 void setup(){ pinMode(BUTTON_PIN, INPUT); Serial.begin(9600); Serial.println("Starting"); } // Returns 1 for high, 0 for low and -1 for unconnected int checkInput(int pin){ digitalWrite(pin, LOW); // Deactivate pull-up, weak pull-down is active if(digitalRead(pin)) { // high, can only be one result return 1; } // Either the pin is pulled down by the pull-down, or by the button digitalWrite(pin, HIGH); // Activate pull-up, overriding the weak pull-down if(digitalRead(pin)) { // high, was only kept low by the pull-down digitalWrite(pin, LOW); // Deactivate pull-up to conserve energy return -1; } digitalWrite(pin, LOW); // Deactivate pull-up to conserve energy // still low, pin is tied to GND return 0; } void loop(){ int state = checkInput(BUTTON_PIN); Serial.println(state); delay(500); } |
So why did I say 1.5 buttons earlier, when you can clearly see 2? Unfortunately, this will not allow you to press both buttons at the same time. If you do, it will be the same result as if only U1 was pressed.
A big advantage of this technique can be had, when you need jumpers to select different modes or settings. Normally 2 pins would result in 2^2 = 4 possible combinations. Using ternary inputs you get 3^2 = 9 combinations. If you have 4 inputs the difference would be 2^4=16 combinations vs. 3^4 = 81 combinations.