Log a quick overview of the latest changes, for your convinience
Projects finished projects, both hard and software
Ideas / How-tos Short articles about technologies, unfinished ideas and other information not related to a specific project
Tidbits Small things, no programming or electronic knowledge required
About about me and this website
23.3.2013

Using internal pull-ups to read tri-state inputs

Schematic for ternary input

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:

Example for ternary input
Arduino
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.

All content of this site is licensed under the CC BY-NC-SA 3.0 license unless otherwise specified.
powered by wordpress