Table of Contents
- Logic Levels and GPIO Pin States
- A Potential Divider
- Resistor and Button as Potential Divider
- The circuit
- Short Circuit
- Limiting Current Flow
- The whole circuit
- Switch Contact Bounce
- Internal pull-up and pull-down Resistors
In reading about using the GPIO pins of either a Raspberry Pi, an Arduino, or some other single-board computer or micro-controller, you have probably seen reference to pull-up and pull-down resistors. But what are they and why do we need them?
Before explaining their use, we need to understand the nature of a general-purpose input/output pin (GPIO pin).
Logic Levels and GPIO Pin States
The purpose of a GPIO pin is to either influence the action of an external circuit, by toggling the high or low state of the pin used as an output, or to monitor the state of some external circuit on a pin configured as an input.
But what do we mean by high or low?
The general-purpose input/output pins on the Raspberry Pi have a high logic level of 3.3 Volts.
In reality there will be a level somewhere between zero volts and 3.3 which represents the threshold above and below which the state is said to be either low (below the threshold) or high (above the threshold).
Let’s assume this threshold is 1.65 volts, half-way between zero and 3.3 volts.
Now let’s assume we have configured one of the pins as an input, to monitor the state of a momentary press button. That is, a button which does not latch, but which has contacts which are closed when it is pressed and open when it is not.
How should we wire this button to the pin, so that when it is pressed, the state of the pin is low, and when it is not pressed, it is high.
The answer is to wire the button so that it forms one part of a potential divider with either a pull-up or a pull-down resistor.
A Potential Divider
What is a potential divider?
Two or more resistances in series across a potential difference, a voltage, form a potential divider, because they divide the potential.
Imagine two resistances of exactly equal resistance, wired in series across a voltage (V).
Imagine that one end of that divider is connected to ten volts, and the lower end is connected to ground, or zero volts.
Measured at the mid-point, the junction between the two resistors, the value measured will be half of the full potential, or 5 volts.
Resistor and Button as Potential Divider
We need a circuit that makes quite sure that when we want the GPIO pin to register as being in the high state, in other words to measure high when the button is not pressed, and to register low when it is, we need to make quite sure the voltages at the GPIO pin are either well below the threshold level (in the low state) or well above it in the high state.
If the level at the GPIO pin is allowed to float or hover at or close to the threshold level we will get false results.
There needs to be a connection between 3.3 volts, with reference to the Pi supply, and the GPIO pin, and the button needs to be wired between the pin and ground.
But why do we need a resistor? Can’t we just connect the 3.3 volt supply directly to the GPIO pin?
The term short circuit, I’ve always thought, is a bit of a misnomer, because it isn’t always particularly short.
It refers to a situation in which excessive current can flow because a very low resistance, typically just a conducting piece of wire, is accidentally connected between a point of high potential, such as the supply rail, and a point of much lower potential, like ground.
If this is allowed to happen, damage can result to components in the circuit, and possibly to the whole assembly because of excessive current flow and the resulting generation of heat.
Limiting Current Flow
So, we need to connect the GPIO pin to 3.3 volts via a resistor so that current is limited.
Refer to the blog post about Ohm’s Law elsewhere on this site for details of how this works.
The whole circuit
Connect a resistor of suitable value between 3.3 volts and the GPIO pin, and one of the push-button’s contacts to the GPIO pin also. Now connect the other contact of the button to ground.
The resistor and the button now form a potential divider.
But, when the button is not pressed, the resistance across it is so high it can be thought of as being open circuit, in fact it is open circuit. If we used a very, very high number of Ohms to represent the open button, and used, for example a 4.7 kilohm resistor, we could calculate that the voltage at the GPIO pin will be as close to 3.3 volts as makes no difference.
But when we press the button, the contacts of it are now so low in resistance, that the situation is reversed, and the 4.7 kilohm resistor is now much, much higher in resistance than the closed contacts of the button.
And here we see the reason for the resistor as opposed to just a piece of wire.
I = V / R (Current = voltage over resistance)
If V is 3.3 and R is 4.7 kilohms then:
I = 3.3 / 4.7
Or a number which is low enough to not cause any damage to the supply, or to generate any significant heat in the circuit. In fact it is below 1 milliamp. Remember from the Ohm’s Law post that if we use a value of kilohms in the calculation, our answer will be in milliamps.
And because the contacts of the button are so low in resistance as to be considered as a short to ground, the voltage measured at the GPIO pin will be almost zero, and well below the threshold.
The above is an example of using a pull-up resistor to make sure that when the button is not pressed the GPIO pin is pulled up close to the 3.3 volt level and well above the threshold, preventing any intermittent state-change events caused by the voltage hovering at or around the threshold.
If we wanted to reverse the situation, to make the GPIO pin register a high state when the button is pressed and a low state when it is not, we could simply swap the button to connect it between 3.3 volts and the GPIO pin, and to wire the 4.7 Kilohm resistor between the GPIO pin and ground.
In this configuration the resistor is again there to limit the flow of current when the button is closed, and because, when the button contacts are open, the resistance it presents is much, much higher than the 4.7 Kilohm resistor, the level measured at the GPIO pin is as near to zero as makes no difference. Hence the resistor is pulling the level down to, or close to ground potential and making sure the pin does not hover around the threshold.
Switch Contact Bounce
There is a complication which, although it is not directly concerned with the subject of this post, is worth mentioning here.
That is the tendency of the contacts of a switch or the contacts of a relay to bounce when they close.
Imagine the button contacts to be two small flat plates of copper which come together when the button is pressed.
If you could record the closure of the contacts at a very high frame-rate and play it back in slow-motion and much magnified, you would observe the contacts bouncing as they come together.
This does not matter at speeds at which humans operate, but at the clock-speed of the CPU in a computer or micro-controller, the result would be a brief but disturbing moment of the high to low state change being repeated several, or even many times.
For this reason electronic circuits typically employ extra components to dampen this bounce and eradicate it’s effects.
The GPIO libraries used in the Raspberry Pi and in the Arduino provide a mechanism for inserting a delay when a state-change is detected to give the contacts chance to stop bouncing, and prevent repeated events from being triggered. Typically this delay is just several milliseconds.
Internal pull-up and pull-down Resistors
Some micro-controllers include internal pull-up or pull-down resistors, and this is true in the case of the Raspberry Pi.
The GPIO libraries provide for configuring code to either use these internal resistors or to employ external ones.
If you could see the state of the junction at the GPIO pin graphed on the screen of an oscilloscope, the change from low-to-high or the change from high-to-low would look like a very rapid rise or fall of the level.
This is called the edge, and it is this which the GPIO libraries used in micro-controllers and that used in the Raspberry Pi typically look for.
If the contacts of our button were not de-bounced, either by adding a delay when the first edge is detected, or by adding other electronic components which clean up this change of state, we would see on the screen what looks like several teeth of a comb as the state rapidly changes from one to the other.