Physical Computing


Links Links

Class Websites

(:source lang=arduino_cpp :)[@
image upload pmwiki-2.2.72, 2002072

 edit SideBar

Arduino General Purpose Input & Output (GPIO) Pins Explained

An explanation of the workings of AVR microcontroller (Arduino) GPIO pins.

Properties of Pins Configured as INPUT

Arduino (Atmega) pins default to inputs, so they don't need to be explicitly declared as inputs with pinMode(). Pins configured as inputs are said to be in a high-impedance state. One way of explaining this is that input pins make extremely small demands on the current of the circuit that they are sampling, say equivalent to a series resistor of 100 megohm in front of the pin. This means that it takes very little current to move the input pin from one state to another. This makes GPIO pins, set to the INPUT state, useful for such tasks as implementing a capacitive touch sensor, reading an LED as a photodiode, or reading an analog sensor with a scheme such as RCTime.

This also means however, that input pins with nothing connected to them, or with wires connected to them that are not connected to other circuits, will report seemingly random changes in pin state, picking up electrical noise from the environment, or capacitively coupling (or following) the state of a nearby pin.

Pulldown and Pullup resistors

Often it is useful to steer an input pin to a known state if no input is present. This can be done by adding a pullup resistor (to +5V), or a pulldown resistor (resistor to ground) on the input, with 10K being a common value.

Pullup Resistors

There are also convenient (approximately) 20K pullup resistors built into the Atmega chip that can be accessed from software. These built-in pullup resistors are accessed in the following manner.

pinMode(pin, INPUT);           // set pin to INPUT state if not already an INPUT
digitalWrite(pin, HIGH);       // turn on pullup resistors

/* this tended to confuse people with the digitalWrite so the language added */

pinMode(pin, INPUT_PULLUP);    // sets the pullup in one step
                               // both forms work, INPUT_PULLUP
                               // is probably preferred for clarity

Note that the pullup resistors provide enough current to dimly light an LED connected to a pin that has been configured as an input. If LEDs in a project seem to be working, but very dimly, this is likely what is going on, and the programmer has forgotten to use pinMode() to set the pins to OUTPUTs.

Note also that the pullup resistors are controlled by the same registers (internal chip memory locations) that control whether a pin is HIGH or LOW. Consequently a pin that is configured to have pullup resistors turned on when the pin is an INPUT, will have the pin configured as HIGH if the pin is then switched to an OUTPUT with pinMode(). This works in the other direction as well, and an output pin that is left in a HIGH state will have the pullup resistors set if switched to an input with pinMode().

Properties of Pins Configured as OUTPUT

Pins configured as OUTPUT with pinMode() are said to be in a low-impedance state. This means that they can provide a substantial amount of current to other circuits. Atmega pins can source (provide positive current) or sink (provide negative current) up to 40 mA (milliamps) of current to other devices/circuits. This is enough current to brightly light up an LED (don't forget the series resistor), or run many sensors, for example, but not enough current to run most relays, solenoids, or motors.

Short circuits on Arduino pins, or attempting to run high current devices from them, can damage or destroy the output transistors in the pin, or damage the entire Atmega chip. Often this will result in a "dead" pin in the microcontroller but the remaining chip will still function adequately. For this reason it is a good idea to connect OUTPUT pins to other devices with 470Ω or 1k resistors, unless maximum current draw from the pins is required for a particular application.

Understanding all of the states of the GPIO (digital) pin

The chart below is based on calling both of the functions (top and left axis of the chart). Note that it does not matter which order in which the functions are called, the state will still result. In the the case of pinMode(INPUT_PULLUP), only one function call is required.

Arduino Function pinMode(pin, INPUT) pinMode(pin, INPUT_PULLUP) pinMode(pin, OUTPUT)
Register states (DDRx register low)
(PORTx register low)

(DDRx register low)
(PORTx register high)

(DDRx register high)
(PORTx register high)

digitalWrite(pin, LOW)
(PORTx register low)

(DDRx register low)
(PORTx register high)

(DDRx register low)
(PORTx register low)

This is the default state of GPIO pins
upon chip power on.

Pin configured as input,
pullup resistors off,
high impedance

pinMode(pin, OUTPUT) digitalWrite(pin, LOW)

Pin configured as output,
Ground (0 volt) level,
pin can sink 40 mA current
(provide negative current)

digitalWrite(pin, HIGH)
(PORTx register high)

pinMode(pin, INPUT)

digitalWrite(pin, HIGH)

pin configured as input
20K pullup resistor on
(20K impedance)

pinMode(pin, INPUT_PULLUP)

same as:
pinMode(pin, INPUT)
digitalWrite(pin, HIGH)

pin configured as input
20K pullup resistor on
(20K impedance)

pinMode(pin, OUTPUT)

digitalWrite(pin, HIGH)

pin configured at output
5 volt level
pin can source 40 mA
(provide positive current)

How can I see these pullup resistors demonstrated.

Here is a copy of the classic "blink" sketch with a couple of changes (besides the comments)
To see this you need to set up an actual LED on a breadboard - or just stick the LED pins
in your Arduino or clones female headers (and ground). The pinMode has been set to INPUT. So instead of blinking the LED brightly, it blinks
the LED dimmly. This is because instead of being able to source 40 mA of current in output mode,
the Arduino is only able to source .25 mA in input mode, so the LED is much dimmer, but still visible.
If your LED is blinking dimmly, in the future, you have probably forgotten to set the pin to OUTPUT
with the pinMode() function.

  Blink - using pinMode()

const LEDpin = 12;  // change to whatever pin you want to use.

void setup() {

  pinMode(LEDpin, INPUT);  // note that pin 13 is set as an input.

void loop() {
  pinMode(LEDpin, INPUT_PULLUP);   // sets the pullup resistor in input mode
  delay(1000);                     // wait for a second
  pinMode(LEDpin, INPUT);          // turns off the pullup resistor in input mode
  delay(1000);                     // wait for a second

What are pullup resistors good for?

Knowing about the internal pullup resistors is important for several reasons. One reason is to know about the side effects that a pullup could cause, for example, when using a high-impedance sensor on an analog input.

The more important reasons to know about the the internal pullup resistors however is to be able to exploit the things that they can do. Below is a short list of applications:

  • Wiring switches with two wires and no fuss. Undoubtedly the largest use of pullup resistors is to be able to wire switches without having to include a third wire or a physical pulldown resistor. Just hook up ground to one side of the switch, turn on the pullup and you're ready to go. There is one slight proviso: The switch will be "active low" instead of "active high".
  • Use the pullups with an external resistor of greater value to read two switches or one three-position switch with one microcontroller pin.
  • Use the pullup on an analog pin to make a voltage divider with a photocell. This only works well if the photocell is in approximately the right range for the 20K internal pullup.
  • The pullup resistors can be used to make a capacitive touch sensor with a single pin. See the Modern Device CapTouch library on Github.

Understanding the port registers that are behind the pins

The best way to really understand the programming of Atmega microcontroller pins used by the Arduino, is to understand the underlying port registers in the Atmega chip. These are the memory locations that control the electrical function of the pins. More details on this may be found in the Port Manipulation reference page.

There are three port registers that control every pin on the Atmega168/328 chip. The lower case x's in the names are place holders for individual port letter designations. This will be more clear if you glance at the Arduino Port Manipulation page.

Port Registers That Control Atmega (Arduino) Pins

DDRx - The Port Data Direction Register - read/write

PORTx - The Port Data Register - read/write

PINx - The Port Input Pins Register - read only

The x in the preceding names is replaced by a letter for the ports. Ports in this case are collections of 8 GPIO pins that all share the same 3 1-byte memory registers mentioned above. Microcontroller ports are generally labelled with letters starting with A or B, and continuing upward as far as necessary to label all the GPIO pins of the chip. Studying the pinmapping of the Atmega 328 chip may make this more clear. For example the pins of Port B are labelled PB0, PB1...PB7

There are four possible states of Arduino digital pins. Analog pins may be used in exactly the same way.

The DDR Register

The DDR register controls whether the pin is an an input or output. So pinMode(pin, HIGH) just sets the proper bit of appropriate DDR register high.
The pinMode() function sets the DDRx register.

The PORT Register

The PORT register controls whether a pin is HIGH or LOW, when the pin is in an OUTPUT state (DDR register set). When the pin is configured to an INPUT state (DDR register reset), the PORT register controls whether the pin has its pullup resistor set.
The digitalWrite() function sets the PORTx register.

As you can see then, the DDR and PORT registers interact in controlling the pin states, so understanding the state of the pin requires understanding both registers.

The PIN Register

The PIN register is a read-only register that indicates the electrical condition of the pin. In other words, if the voltage level at the pin is above about 2.5 volts, the corresponding bit of this register will read as a 1, if not it will read as a 0. The PIN register cannot be written, since its value depends on the external voltage level of the pin.
The digitalRead() function reads the PINx register which is controlled by the voltage at the pin.

Digital Pins

The pins on the Arduino can be configured as either inputs or outputs, as a start but actually they have four states, as shown in the table above. This document explains the functioning of the pins in those modes. While the title of this document refers to digital pins, it is important to note that vast majority of Arduino (Atmega) analog pins, may be configured, and used, in exactly the same manner as digital pins.

Related Reference Reading

Edit - History - Recent Changes - Search
Page last modified on September 25, 2016, at 08:56 PM