GPIO — study guide

The concept's fragments, read in order.

A pin the software points either way

one GPIO pin, two directions set by software OUTPUT mode chip chip drives pin HIGH or LOW pin load (LED) INPUT mode chip chip reads pin's level pin source (button)
The same GPIO pin works two ways: as an output the chip drives the pin HIGH or LOW, as an input the chip reads whether the pin is HIGH or LOW.

A microcontroller talks to the world through its pins, and the most basic kind is the general-purpose input/output pin, almost always shortened to GPIO. General-purpose is the whole idea: the pin has no fixed job baked into the silicon. One program can use it to switch a light on, and the next can use the very same pin to notice a button being pressed. like a doorway a building can set as an entrance or an exit: the opening is the same either way, and only the setting decides which direction it works

The catch — and the thing that keeps this simple — is that a plain GPIO pin deals in exactly two states. As an output it drives the pin to one of two voltages: HIGH, near the supply rail, or LOW, near ground. As an input it reads the pin's voltage and reports back just HIGH or LOW against the same logic bands any digital part uses. There is no in-between value here; a pin that needs to make an analog-like output or read a smoothly varying voltage reaches for separate techniques that come later.

So the entire concept is two verbs on a two-state pin: write a level out, or read a level in, one pin at a time. Everything else — which way the current runs, why a released button reads garbage, how you tell the pin which verb it is doing — is detail hung on those two verbs. It is the plainest possible way for a chip to touch the physical world, and it is where nearly every hardware project starts.

Telling a pin what to be

Because a GPIO pin has no fixed job, the first thing any program does with one is declare its intent. That declaration is the pin's direction: is this pin an output the chip drives, or an input the chip reads? Nothing sensible happens until the direction is set, because the hardware behind the pin is wired differently for the two jobs — an output connects the pin to the chip's internal drivers, while an input connects it to the chip's sensing circuit.

Setting direction is a write to a control register, a small block of bits inside the chip where each bit governs one pin. In hand-written register code that looks like flipping a single bit; in the friendly libraries most people use it is one line naming the pin and the direction, something like a pinMode call marking a pin as an input or an output. The pin keeps that role until the code changes it, and the same pin can be reconfigured mid-program if the design calls for it.

Direction is the main setting, but configuring a pin can carry a little more: its mode. The most common mode option is whether to switch in an internal pull resistor, a small on-chip helper for input pins. The point to hold onto is that a GPIO pin is defined in software before it is used — the physical pin is generic, and code is what gives it a direction and a job.

Driving a pin high or low

An output pin is the chip reaching out and setting a voltage. Write HIGH to it and the chip connects the pin to its supply rail, so the pin sits near the logic voltage — 3.3 V or 5 V, depending on the board. Write LOW and the chip connects the pin to ground, so it sits near 0 V. Those two commands are the entire output vocabulary, and between them they can switch anything that only needs to be on or off.

The classic first output is lighting an LED. Wire the LED from the pin through a resistor to ground, drive the pin HIGH, and current flows through the LED and it lights; drive the pin LOW and the pin and ground sit at the same voltage, no current flows, and it goes dark. The resistor is not optional — it is a current-limiting resistor, sized so the LED and the pin pass a safe current rather than as much as they physically can, which would be too much for both.

The same on/off control scales up to real loads — a relay coil, a buzzer, the enable line of some other part — as long as the load stays within what a pin can safely drive. Blinking an LED is the traditional first program precisely because it exercises the whole output idea in three lines: set the pin as an output, write HIGH, write LOW. What a pin can and cannot drive directly is the next question, and it comes down to current.

Which way the current flows, and how much

same LED, two current directions SOURCING: pin driven HIGH pin = HIGH resistor LED ground current out of pin SINKING: pin held LOW supply resistor LED pin = LOW current into pin
Sourcing versus sinking: a pin driven HIGH pushes current out of the pin through the load to ground, while a pin held LOW lets current flow from the supply through the load into the pin.

A driven pin does not just set a voltage; it passes current, and there are two directions that current can run. When a pin is HIGH and the load hangs between the pin and ground, current flows out of the pin, through the load, to ground — the pin is sourcing current. When a pin is LOW and the load hangs between the supply and the pin, current flows from the supply, through the load, into the pin — the pin is sinking current. like a tap that can either push water out through whatever it feeds or, plumbed the other way, accept water draining down into it: same fitting, opposite direction of flow Both light the LED; they just wire it the other way up and drive the pin to the opposite level to turn it on.

The reason this matters is that a GPIO pin can only pass so much current, in either direction, before it is stressed or destroyed. The limit is small — a few tens of milliamps. An Arduino Uno's ATmega328P pin is rated around 20 mA as a comfortable continuous figure and 40 mA as the absolute maximum; a Raspberry Pi pin should be kept to about 16 mA. There is a whole-chip ceiling too, not just a per-pin one: the ATmega328P caps the total across all its pins near 200 mA, and a Raspberry Pi near 50 mA across all its GPIO, so you cannot quietly run every pin at its own maximum at once.

That budget is why an LED gets a series resistor and why anything hungrier does not connect to a pin at all. A motor, a bright lamp, a long strip of lights — each wants far more current than a pin can source or sink, so the pin instead switches a driver, a separate part built to handle the load while the pin only tells it when. The pin commands; the muscle lives elsewhere.

Reading a pin as high or low

Turn a pin around and it becomes a sensor for one bit of the outside world. As an input the chip does not drive the pin at all; it measures the voltage on it and sorts that into one of two answers. A voltage near the supply rail reads HIGH, a voltage near ground reads LOW, judged against the same logic bands that let any digital part agree on ones and zeros. A single read returns just that one bit: is this pin up or down right now.

The everyday example is a pushbutton. Wire the button so that pressing it connects the pin to a known voltage — to ground, say — and the code can read the pin to learn whether the button is down. Poll the pin in a loop and you have the raw material of every switch, limit stop, and contact sensor a project needs: a value the program can branch on. Reading is cheap and instant, so a program can check a pin thousands of times a second if it wants to watch for a change.

There is one quiet assumption buried in all of this, and it is where beginners get bitten: reading a pin only works if the pin is actually being held at a voltage. A button that is pressed pins the input to a known level, but a button that is released leaves the pin connected to nothing at all — and an input connected to nothing does not politely read LOW. That is the floating input, and it is the next thing to get right.

The pin connected to nothing

An input pin reports the voltage it finds, which is fine as long as something is setting that voltage. The trap is the moment nothing is: an input wired to an open switch, or left unconnected on the board, is not tied to the supply or to ground by anything. It floats. And a floating input has no defined level to report — it will read HIGH sometimes and LOW other times, with no press or signal behind the change.

The reason is that the tiny sensing circuit behind an input draws almost no current, so it takes almost nothing to move the pin's voltage around. Stray capacitance, a nearby wire switching, even a fingertip near the board couples in enough to swing a disconnected pin across the threshold. like a loose microphone left switched on: connected to nothing in particular, it does not fall silent but hums and pops with whatever electrical noise is in the room The pin faithfully reports these ghosts, so a program reading a floating input sees a value that flickers on noise rather than on anything real.

This is exactly the released-button problem. Press the button and the pin is held at a known level and reads cleanly; let go and the pin is connected to nothing, floats, and the reading becomes noise. A digital input has two honest states, HIGH and LOW, and floating is the dangerous third: undefined. The fix is never to leave an input floating — to make sure that when nothing else is driving the pin, something still gently holds it at a known level.

Pull-ups and pull-downs give a default

a pull-up sets the default, the button overrides it supply (3.3 V or 5 V) pull-up resistor weak: tens of kilohms input pin reads here button (shown open) ground button open: pin pulled to supply, reads HIGH button pressed: pin tied to ground, reads LOW
A pull-up resistor holds the input HIGH while the button is open; pressing the button connects the pin to ground so it reads LOW.

The cure for a floating input is to give it a default. A pull-up resistor connects the input to the supply rail, so when nothing else is driving the pin it is gently held HIGH. A pull-down resistor connects it to ground instead, so the resting state is LOW. Either way the pin now has a defined level to read whenever the outside world lets go of it, and the flickering stops.

The trick is that the resistor is deliberately weak — a high value, typically tens of kilohms. That weakness is the whole point. like a lightly sprung door that rests closed on its own but swings open the moment anyone actually pushes it: firm enough to set a default, weak enough to be overruled When a button or another part actively drives the pin the other way, it easily overrides the gentle pull, so the pin snaps to the driven level; only a tiny current trickles through the resistor while it does. A common wiring is a pull-up plus a button to ground: the pin reads HIGH at rest and LOW while the button is pressed. The logic reads inverted from what a beginner expects, which is worth saying out loud before it causes a puzzled afternoon.

Most microcontrollers spare you an external resistor by building the pull-up in. An internal pull-up is an on-chip resistor of the same tens-of-kilohms size — around 20 kΩ to 50 kΩ on an ATmega328P, roughly 50 kΩ on a Raspberry Pi — that software switches in as part of a pin's mode. Enable it in the same breath as setting the pin to input and the floating problem is gone with no parts added; many chips offer an internal pull-down as well. Reaching for the internal pull-up is the routine way to read a button, and it is why configuring an input is usually two decisions, not one: direction, and which default to hold.

Every wire in or out of the brain

GPIO is the ground floor of a microcontroller touching anything. Before a build does anything clever, it has pins that go HIGH and LOW and pins that read HIGH and LOW, and that plain digital in-and-out is the surface every richer technique is built on. Learn to drive a pin, read a pin, respect the current limit, and hold an input at a known level, and you have the whole vocabulary of a chip's simplest conversation with the physical world.

For a build like a small self-driving car, the count of GPIO uses adds up fast. An output line tells a motor driver to enable a wheel or flips a status light; an input line reads a bumper switch or a start button. Each of those is a single pin doing one of the two verbs, wired with the same care about which way the current runs and whether a released contact leaves an input floating. Get a pin's direction or its pull wrong and the symptom is maddening — a car that lurches on electrical noise, or a sensor the code never sees change.

The richer signalling most parts actually use — sending a smoothly varying command to a motor, reading a sensor's analog voltage, having a pin interrupt the processor the instant it changes, or clocking whole streams of data between chips — all sits on top of this. Those are later concepts, and every one of them assumes a pin you can already set, read, and keep out of the floating no-man's-land. GPIO is the first handshake between the code and the copper, and nothing physical happens until it works.