GPIO
GPIO pins are the simplest way for a program to reach the outside world. The name stands for general-purpose input/output: each pin is a wire that your program controls.
As an output, a pin is a switch your program flips. High connects it to 3.3 volts, and low connects it to ground. That's enough to light an LED or to signal another chip.
As an input, a pin tells your program what voltage it sees, as high or low. That's how a program reads a button, or a sensor that only ever says yes or no.
An input with nothing connected is said to be floating. With no voltage holding it in place, the pin acts like a tiny antenna, picking up stray signals from the wires and electronics around it, so it can read high one moment and low the next.
A pull-up or pull-down gives the pin a resting value. It's a weak connection inside the chip, to 3.3 volts or to ground, that holds the pin at that level while nothing else is driving it. Anything stronger, such as a pressed button, can still pull it the other way.
The Pi's pins work at 3.3 volts, and 5 volts can damage them. They also supply very little power: keep each pin to about 16 milliamps. That lights an LED, but it won't turn a motor, which needs an amplifier circuit or a driver board, such as the LEGO Build HAT.
What uses it
- LEDs, on and off
- Buttons and switches
- Motion sensors, such as the HC-SR501, which say only "something moved"
- Reed switches, which close near a magnet
- Reset lines on other boards: the Build HAT library resets its HAT this way
Finding the pins
Every pin has two numbers, and they don't match, because they come from different places. The GPIO number comes from the processor, which numbers its own input and output lines. The pin number comes from the Raspberry Pi board: it's where that line ends up on the header, counting from pin 1. Your code uses the GPIO number.
So Pi.digitalOutput(17) means GPIO 17, which is pin 11. Pin 17 is 3.3 V power. Count from
pin 1 before you connect anything: a wire on the wrong pin can put 5 volts on a pin that can't
take it, and that can destroy the board.
- Free to use
- Free until PWM uses it
- Refused: it belongs to a bus or the board
- Power
- Ground
Not every pin is yours to use. digitalOutput and digitalInput refuse the pins that I²C,
SPI and UART use, and GPIO 0 and 1, which the board uses to identify a HAT. Thirteen pins are
always free: GPIO 4, 5, 6, 16, 17, 20, 21, 22, 23, 24, 25, 26 and 27. GPIO 12, 13, 18 and 19 are
free too, until PWM uses them.
Light an LED
You'll need an LED, a 330 Ω resistor, a breadboard and two jumper wires. The resistor limits the current to about 4 milliamps, which protects both the LED and the pin. An LED only works one way round: its longer leg goes towards the pin.
- Pin 9GNDTo the LED's short leg
- Pin 11GPIO 17To the resistor, then the LED's long leg
Pi and its devices come from a library, not from the language, so this code won't build
without it. In IntelliJ, choose Tools | Nylon | Add Nylon Library… and pick raspberry-pi. That adds
one line to your project's build.markup.code:
(+dependencies : RepositoryDependency coordinate={"com.grandtheorem:raspberry-pi:0.1.0"} /)
Every file starts with its namespace. Pi is the board, and nylon.time gives us sleep.
namespace led
import grandtheorem.rpi.Pi
import namespace nylon.time
Ask the board for GPIO 17 as an output. The number is the GPIO number, not the position on the header.
entrypoint.default main() {
let led = Pi.digitalOutput(17)
write(true) drives the pin high, which lights the LED. Then wait half a second.
for (10 times) {
led.write(true)
sleep(500.milliseconds())
write(false) drives it low, and the LED goes out.
led.write(false)
sleep(500.milliseconds())
}
}
The LED flashes ten times, and the program ends.
Read a button
Keep the LED where it is, and add a button. Pressing it joins GPIO 4 to ground.
- Pin 6GNDTo one side of the button
- Pin 7GPIO 4To the other side of the button
Pull comes from the devices library, which the Raspberry Pi library brings with it.
namespace button
import grandtheorem.rpi.Pi
import grandtheorem.devices.Pull
import namespace nylon.time
Ask for GPIO 4 as an input with its pull-up on, so it reads high until the button pulls it to ground. The LED is an output, as before.
entrypoint.default main() {
let button = Pi.digitalInput(4, Pull.Up)
let led = Pi.digitalOutput(17)
read() answers true for high, so a pressed button reads false. ! flips that into
what we mean.
while (true) {
let pressed = !button.read()
led.write(pressed)
Wait a moment before looking again, so the loop isn't flat out.
sleep(10.milliseconds())
}
}
The LED stays lit for as long as you hold the button. This program loops forever, so press Stop in IntelliJ to end it.
Good to know
Buttons bounce. Metal contacts chatter for a few milliseconds as they close, so one press can look like several. It doesn't matter here, but it will if you count presses.
The board has an LED of its own. Pi.statusLed() gives you a light with no wiring at
all, so Pi.statusLed().blink(3) is the smallest program that does something you can see.
These programs ran on a Raspberry Pi 3 B+, as this page shows them.