Using Digital I/O Pins

NumTeensy
1.0
Teensy
2.0
Teensy++
1.0 or 2.0
0PIN_D0PIN_B0PIN_D0
1PIN_D1PIN_B1PIN_D1
2PIN_D2PIN_B2PIN_D2
3PIN_D3PIN_B3PIN_D3
4PIN_D4PIN_B7PIN_D4
5PIN_D5PIN_D0PIN_D5
6PIN_D6 *PIN_D1PIN_D6 *
7PIN_D7 +PIN_D2PIN_D7
8PIN_SSPIN_D3PIN_E0
9PIN_SCLKPIN_C6PIN_E1
10PIN_MOSIPIN_C7PIN_C0
11PIN_MISOPIN_D6 *PIN_C1
12PIN_B4PIN_D7PIN_C2
13PIN_B5PIN_B4PIN_C3
14PIN_B6PIN_B5PIN_C4
15PIN_B7PIN_B6PIN_C5
16PIN_C7PIN_F7PIN_C6
17PIN_C6PIN_F6PIN_C7
18PIN_C5PIN_F5PIN_E6
19PIN_C4PIN_F4PIN_E7
20PIN_C2PIN_F1PIN_B0
21PIN_F0PIN_B1
22PIN_D4PIN_B2
23PIN_D5PIN_B3
24PIN_E6PIN_B4
25PIN_B5
26PIN_B6
27PIN_B7
28PIN_A0
29PIN_A1
30PIN_A2
31PIN_A3
32PIN_A4
33PIN_A5
34PIN_A6
35PIN_A7
36PIN_E4
37PIN_E5
* LED (LOW=on, HIGH=off)
+ HWB (bootloader select)
The Teensy has 21 digital I/O pins and the Teensy++ has 38, which you can use to control many types of devices or read information.

You can access the pins by their number, or using their pre-defined names shown in the table. These names match the printing on the circuit board.

Input vs Output: pinMode()

When your sketch begins running, all digital pins default to input mode.

You can control the mode of any pin using the pinMode() function. For example:

  pinMode(PIN_D6, OUTPUT);

The first parameter is the pin number to configure and the second parameter must be either INPUT or OUTPUT.

Often pinMode() is used in the setup() section to configure all the digitial pins that are used and they simply remain that way. However, you may change any pin at any time.

Output: digitalWrite()

When a pin is configured as output, you can make it high or low by calling digitialWrite().

  digitalWrite(PIN_D6, LOW);  // LED on

  digitalWrite(PIN_D6, HIGH); // LED off

Output: digitalToggle()

When a pin is configured as output, you can change its state using digitalToggle(pin).

Input: digitalRead()

When a pin is configured as an input, you can read it with digitalRead(), which returns 0 if the pin is low, or 1 if the pin is high. The result is usually used with an if statement to run different code depending on the voltage on the pin.
  if (digitalRead(PIN_C2)) {
    // do this if C2 is high
  } else {
    // do this if C2 is low
  }

Input With Pullup

All of the pins have a pullup resistor which may be activated when the pin is an input. Just use pinMode() with INPUT_PULLUP.
  pinMode(PIN_D7, INPUT_PULLUP);
The pullup resistors are useful when connecting pushbuttons that can connect the pin to ground (low), but when the button is not pressed there is no connection at all. The pullup resistor causes the voltage to be high when nothing is connected.

A brief delay may be needed between pinMode() configuring INPUT_PULLUP mode and digitalRead() reporting the unconnected pin as HIGH. The pullup resistor raises the voltage slowly, depending on capacitance of any circuitry attached, plus the capacitance of the pin and breadboard or wires. Usually delayMicroseconds(10) is plenty.

The INPUT_PULLUP option is a Teensy extension which is not present on the official Arduino.

Active Low vs Active High

Intuitively, most people think of a logic HIGH signal to mean "on" or "active" and a logic LOW signal to mean "off" or "inactive". This scheme is called "Active High". However, the opposite scheme is often used in electronic circuits.

"Active Low" may seem backwards, but is often used because the transistors that cause the signal to be low are more efficient. Some chips, such as infrared receiver modules, have "open collector" outputs, which simply means they work the same way as the pushbutton, where they connect to ground but do not include the ability to output a high signal at all. Because this signal type is so common, every pin includes the optional pullup resistor.

Most projects end up using Active High for some signals and Active Low for others. A common convention is to draw a line over the top of the signal name if it is Active Low.

A Complete Example

This simple example blinks the LED slowly when the pushbutton is not pressed, and blinks rapidly when it is pressed. The pushbutton is connected to the D7 pin and ground, and the pullup resistor is used to make the pin high when the button is not connecting it to ground.
void setup()
{
  pinMode(PIN_D6, OUTPUT);       // LED
  pinMode(PIN_D7, INPUT_PULLUP); // Pushbutton
}

void loop()
{
  if (digitalRead(PIN_D7)) {
    // D7 pin is high due to pullup resistor
    digitalWrite(PIN_D6, LOW);   // LED on
    delay(400);                  // Slow blink
    digitalWrite(PIN_D6, HIGH);  // LED off
    delay(400);
  } else {
    // D7 pin is low due to pushbutton pressed
    digitalWrite(PIN_D6, LOW);   // LED on
    delay(80);                   // Fast blink
    digitalWrite(PIN_D6, HIGH);  // LED off
    delay(80);
  }
}
This very simple code only tests the D7 pin at the beginning of each blink. If a slow blink begins just before the button is pressed, there is a noticable lag time until the rapid blinking begins. A more sophisticated approach would involve writing a custom delay function that immediately aborts if the D7 pin changes.

TODO: link to page about timekeeping and delay functions (when it's written)