Explainer · Intermediate · about 40 minutes
UART, I2C and SPI
Microcontrollers talk to sensors, displays and memory chips by sending bits one after another down a few wires. See exactly what is on each wire, bit by bit, as a logic analyser would show it, for the three buses you will meet in almost every project.
Sending bits one at a time
A byte is eight bits. Sending them one after another on a single wire is called serial communication. The receiver must know when each bit starts, so every bus has a way to keep time:
- UART agrees a speed in advance (the baud rate) and marks the start of each byte with a start bit.
- I2C and SPI send a clock on a separate wire: each tick says “read the data now”.
The chip that starts each conversation is the controller (usually your microcontroller); the chips it talks to are peripherals. Older documents call them master and slave.
A logic analyser records several digital wires at once and shows them as rows of highs and lows over time, decoding the bytes for you. The view below works the same way.
Logic analyser
sent by the controller sent by the peripheral not driven Hover over a bit for what it means.
What the receiver decodes
What is happening
Model: ideal digital signals with instant edges. The decoded lines are produced by reading the drawn waveforms back the way a real receiver samples them. Real signals have slopes, and I2C rises more slowly through its pull-up resistors.
Which bus?
| UART | I2C | SPI | |
|---|---|---|---|
| Wires (plus ground) | TX and RX | SDA and SCL, shared by every chip | SCK, MOSI, MISO, and one CS per chip |
| Timing | Agreed baud rate | Clock from the controller | Clock from the controller |
| Choosing a chip | One device per pair of wires | 7-bit address in every message | Pull that chip’s CS low |
| Typical speed | 9600 to 115200 baud | 100 or 400 kHz | 1 to tens of MHz |
| Typical parts | USB serial to a computer, GPS, Bluetooth modules | Small displays, temperature and motion sensors, clocks | SD cards, flash memory, fast displays |
Wiring and code
UART
Cross the wires: TX of one goes to RX of the other. On an Arduino Uno, pins 0 and 1 are the same UART the USB uses, so disconnect anything on them while uploading. The Serial monitor shows what a sketch sends.
Serial.begin(9600);
Serial.print("Hi");
I2C
Each line needs a pull-up resistor to the supply (often 4.7 kΩ; many modules have them already). Chips only ever pull a line low or let it go: that is what lets many chips share two wires safely. On an Uno, SDA is A4 and SCL is A5.
#include <Wire.h>
Wire.begin();
Wire.beginTransmission(0x3C);
Wire.write(0x00); Wire.write(0xAF);
Wire.endTransmission(); // 0 means the device answered
SPI
SCK, MOSI and MISO are shared; each chip gets its own CS (chip select) line, held high when idle. Newer documents name MOSI and MISO as COPI and CIPO. On an Uno they are pins 13 (SCK), 11 (MOSI) and 12 (MISO); any free pin can be a CS.
#include <SPI.h>
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
digitalWrite(CS_PIN, LOW);
SPI.transfer(0x9F);
byte maker = SPI.transfer(0x00);
digitalWrite(CS_PIN, HIGH);
SPI.endTransaction();
A 5 V Arduino can damage a 3.3 V chip. Check the chip’s supply and input voltages, and use a level shifter (or a module that has one) between 5 V and 3.3 V parts. Always connect the grounds.