John L Errington MSc

John Errington's Experiments with an Arduino

Using digital inputs: Switches and buttons

Introduction

All the Arduino family of microcontrollers have pins that may be used as inputs. This article looks at some alternative ways of connecting digital input devices - switches and buttons.

On this page:

  1. Pins of the arduino family
  2. Equivalent circuit for a digital input pin
  3. Arduino logic levels and voltages
  4. Using buttons and switches for inputs
  5. Pull up (and pull-down) resistor values
  6. Digital input characteristic and hysteresis levels

Pins of the arduino family

To give maximum flexibility each external connection on and Arduino board may share different functions. Lets look at some examples on the Arduino Nano; I'll refer to the pin numbers as shown on the board itself.

 

Pro Micro 32U4

Pin 7: Digital Input or Digital Output

Pin 4: Digital Input, Digital Output or Analog input

Pin 5: Digital Input, Digital Output or Pulse Width Modulated output

 

Each member of the Arduino family has differences so you will need to check the pin configuration for the Arduino you are using.

However a common factor is that for all Arduinos

A pin that is not programmed behaves as a digital input,
in the same way as if it was declared as
pinMode(pin, INPUT)

In the following information, unless otherwise stated all data and values are taken from the data sheet for the ATMega328P which powers the Arduino Nano. Most Arduinos use the 328 or 32U4 chips; the later Due, Zero and others use more powerful processors that run from 3.3V however the electrical characteristics are similar.

Digital pins configured as inputs

Sense current

A digital pin configured as an input has a very high impedance; in effect it behaves very much like an open circuit. The CMOS circuit presents a very high resistance, and can pick up stray signals or static electricity which could damage the circuit. Diodes D1 and D2 prevent this by constraining the input to voltages between 0V and Vcc.

Input voltage: Vin >0V and Vin <Vcc

Input resistance Rin >100Mohm

The 32U4 and 328 data sheets show the maximum value of leakage current at an input pin as 1uA. This corresponds to an effective input resistance of MORE THAN 5Mohm. However the data sheet for the ATMel Cortex SAM3 as used on the Arduino Zero and Due gives a more realistic value typically of 2 - 5 nA. 5V/5nA = 1Gohm.

Input capacitance Cin - "typically a few pF"; I havent been able to find a specified value for this but this is the general guidance for many CMOS circuits.

"Logic levels"

logic levelsThis diagram shows the "logic levels" for the 328 and 32U4 processors when used on a 3.3V or 5V supply.

So for a Nano or Pro Micro running from a 5V supply we see:

  • Input pin voltages above 5V or below 0V are not allowed as they would damage the processor.
  • A voltage between 3.0V and 5.0V will be read as a logic "1"
  • A voltage between 0.0V and 1.5V will be read as a logic "0"
  • A voltage between 1.5V and 3.0V will always give a reading of a "1" or a "0" ..

- but we cant say which it will be. This region gives an "undefined" value, so in normal use we must avoid such an input voltage.

More about the "undefined" region in the section below on hysteresis.

 

The following circuits show how these conditions can be met.

Buttons, switches, pull up (and pull down)

In using a switch or push button to provide a digital input to the Arduino we basically have two options as shown here; to connect the switch or button to the ground 0V rail - which is generally the preferred option; or to connect it to the +Vcc rail. Lets look at some simple configurations.

buttonsThe usual choice is to use a ground connected "normally open" button or switch. This has many advantages - but the "active" (pressed) condition of the button results in a logic "0" and inactive or released condition gives a "1"

Here we see good and bad implementations of a push button connected between a digital pin and the ground rail.

PB1 will generate a good logic 0 when pressed; but when its open Pin D1 will be floating and give unpredictable results. Most likely it will NOT immediately go to a logic 1 when released.

The circuit around PB2 / Pin D2 shows the correct implementation; before the button is pressed, and after it is released, Rpu the pull-up resistor will ensure it is at the correct voltage to generate a good logic 1.

 

 

Here we see a button connected to the Vcc rail. Pin D3 will be at a logic "1" when the PB3 button is pressed - but when its released the value will be indeterminate because the input is floating.

PB4 shows the "correct" implementation. We need a "pull-down" resistor to ensure Pin D4 is at a logic zero when the button is released.

Its also good practice to include a "protection" resistor, as if the button is inadvertently wired to the wrong supply rail an excessive current can flow into the pin, damaging the circuit.

Here we see switches used to provide inputs.

buttons

The first figure here shows a switch connected to the ground rail, with a pull-up resistor. It will work fine, giving a good "logic 0" voltage at pin D5, and changing to a good "logic 1" when activated.

So what is wrong with the next circuit? We are using a change-over switch, with an external resistor.

With SW2 in position 1 a good logic zero appears at pin D6. When its in position 2 D6 gets a good logic 1.

The problem is that as the switch passes between those positions the D6 input is left open-circuit and logic level undefined.

This issue is fixed by moving the pull-up resistor as shown below SW4 / D8. As soon as the switch leaves position 1 Rpu takes the voltage to logic 1.

 

Our final example shows how a multi-position switch can feed data to the Arduino. The Rpu / Pin combination shown is just repeated for each position.

This example just shows a 2 way switch, but rotary switches are available in many configurations.

 

On this page you can see how a multi-way switch can be used and coded with diodes to reduce the number of inputs that need to be committed; for example a 12 way switch could be coded to need only 4 digital pins.

Values for pull-up, pull down, and protection resistors

For most purposes the internal pull-up resistor is sufficient. It is connected by declaring a pin as

pinMode(pin, INPUT_PULLUP) and would replace the external pull-ups shown above.

In this circuit we need to be more careful. The pin should be declared as pinMode(pin, INPUT) which disconnects the internal pull-up resistor.

Now the pull-down resistor can be any practical value, because of the high input resistance of the Arduino pin. However
a high impedance is a disavantage in digital circuit as it exposes the connection to picking up stray signals; So

Lets choose a value for Rpd of 100kOhm. When PB4 is open Pin D4 will be at or around 0V.

Now if Vcc matches Vcc for the Arduino we need to choose Rprot so that Pin D4 lies securely in the logic 1 region when the switch is closed. For all Arduinos a voltage between Vcc and 0.7*Vcc will be a good logic 1.

So, if we choose 33k for Rprot the voltage on D4 will be Vcc * Rpd/Rprot + Rpd = Vcc * 100k/100k + 33k = 0.75 * Vcc

That's a good logic 1. You can adjust the value chosen for Rprot to suit any external positive voltage.

We can debounce the switch action by adding a small capacitor from D4 to ground. (see next section)

Digital input characteristic and hysteresis levels

hysteresis

This graph shows how an input voltage on a digital input will be treated.

The top (red VIH) line shows the voltage above which an input will DEFINITELY be recorded as a "HIGH"

A voltage below the (DARK BLUE VIL) line will DEFINITELY be read as a "LOW" or logic "0"

The orange "Vih" and cyan "Vil" lines show hysteresis levels. For Arduino's running from a 5V supply these voltages are

VIH = 3.0V; Vih = 2.6V; Vil = 2.2V; VIL = 1.5V

The effect of these hysteresis levels is shown on the next graph

hysteresis levelsThis shows how the digital input responds to a changing signal. The blue line shows a ramp voltage applied to a digital input pin. It starts at just over 1V which is in the "logic 0" region between 0V and VIL; so of course this is read by the arduino as a logic "0". The red line represents the logic level.

Note the logic level stays at zero as we move above VIL. We are now in the "indeterminate" band, and it is the hysteresis levels that determine how the input will be represented.

The logic level does not change until Vin exceeds Vih. At that point it transitions to a logic "1". It remains there as we pass into the "logic 1" region between VIH and Vcc.

Now as the input voltage is decreasing, the logic level remains at a "1" as Vin falls out of the "logic 1" band; and stays at a "1" until Vin < Vil.

At that point, still in the "indeterminate" band, the logic level falls to a "0"