Unit D - Sensors & Buses

23. UART, I2C & SPI Reference

Choose and troubleshoot common embedded communication buses.

Estimated time 3 hours

Learning outcomes

  • Compare UART, I2C and SPI by wiring, speed and how devices are selected
  • Identify Uno hardware pins for UART, I2C and SPI
  • Explain I2C addresses and SPI chip-select
  • Choose a suitable bus for GPS, RTC and SD-style modules
  • Run an I2C address scan with Wire

Parts and preparation

Arduino Uno and any I2C and/or SPI modules available in the kit (optional for the scan demo).

Before power: inspect wiring, confirm supply voltage and ensure all connected circuits share GND.

Libraries for this lesson

In Arduino IDE 2 open Tools → Manage Libraries…. Search by the Library Manager name and install the package by the exact author below. Similar names from other authors can use different APIs and will break the example.

IncludeLibrary Manager nameAuthorInstall note
Wire.hWireArduinoBuilt into the Arduino core. No Library Manager install required.
SPI.hSPIArduinoBuilt into the Arduino core. Used later with SD / RFID modules; not required for the I2C scanner sketch.
UART, I2C & SPI Reference instructional connection diagram

Three buses at a glance

UART, I2C and SPI are the three buses you will meet most often in this course. They all need a common GND and matching logic voltage. They differ in how many devices share the wires, whether a clock line is shared, and how a device is selected.

This lesson is a reference: use it when wiring an unfamiliar module or when a project needs more than one device on the Uno.

Three columns comparing UART, I2C and SPI for wires, device count and typical course modules
UART for one partner, I2C for several low-speed modules, SPI when speed and chip-select fit.
BusSignal wires (typical)How devices are chosen
UARTTX, RX (+ GND)Usually one partner per UART
I2CSDA, SCL (+ GND)7-bit address on the shared bus
SPISCK, MOSI, MISO, CS (+ GND)Chip-select pin per device

UART

UART is asynchronous: both ends agree a baud rate (for example 9600) and send bytes without a shared clock wire. Wire TX of one device to RX of the other, RX to TX, and share GND. That crossover is easy to get wrong once.

On the Uno, hardware UART is D0 (RX) and D1 (TX). The USB Serial Monitor uses the same UART through the board USB bridge, so a GPS or other module on D0/D1 can block uploads or garble Serial output. SoftwareSerial on other pins is possible later; start by knowing D0/D1 are special.

Uno TX connected to device RX and Uno RX connected to device TX with shared GND
Cross TX to RX. Match baud. Unplug D0/D1 modules if uploads fail.

I2C

I2C is a two-wire shared bus: SDA carries data and SCL carries the clock. Several devices can share those wires because each has an address (for example LCD 0x27, RTC 0x68). Pull-up resistors hold idle lines HIGH; most modules include them (lesson 17).

On the Uno, SDA is A4 and SCL is A5. Use Wire.h. If a device stays silent, run the I2C scanner in this lesson before rewriting application code.

Uno master on shared SDA and SCL lines with LCD, RTC and sensor at different I2C addresses
One SDA and one SCL for every device. Addresses keep them separate.

SPI

SPI is clocked and usually faster than I2C for bulk data. SCK is the clock, MOSI carries controller-to-device data, MISO returns device-to-controller data. Each device normally needs its own CS (chip select) pin. Only one CS is active (usually LOW) at a time; idle CS lines stay HIGH.

On the Uno, hardware SPI is D13 (SCK), D11 (MOSI), D12 (MISO). D10 is often used as SS / CS for the first device and also appears on the ICSP header. SD cards and RFID modules in later lessons use this pattern.

Uno sharing SCK MOSI MISO with an SD card on CS D10 and an RFID module on CS D7
Shared data lines; separate CS per chip. Idle CS stays HIGH.

Uno pin map

Memorize the hardware pins for this course. They are fixed on the Uno R3 - swapping them casually usually means you are no longer using the hardware peripheral.

Cards listing Uno UART pins D0 D1, I2C pins A4 A5, and SPI pins D11 D12 D13 D10
UART D0/D1, I2C A4/A5, SPI D11/D12/D13 (+ CS, often D10).
BusUno R3 pins
UARTD0 RX, D1 TX
I2CA4 SDA, A5 SCL
SPID13 SCK, D11 MOSI, D12 MISO, CS as chosen (often D10)
SPI altSame SPI signals on the ICSP header

Choosing a bus

Match the module datasheet first - you rarely get to invent the bus. When you do choose: UART for one serial partner (GPS, PC text), I2C when several sensors/displays must share two wires, SPI when you need speed or the part is SPI-only (SD, many RFID readers).

Voltage matters: a 3.3 V SPI flash or sensor may not tolerate 5 V Uno pins. Always check logic levels before connecting.

Decision cards recommending UART for GPS, I2C for RTC and LCD, SPI for SD and RFID
Challenge anchor: GPS UART, RTC I2C, SD SPI.

I2C scanner sketch

The worked sketch walks every 7-bit address and prints those that acknowledge. Wire.begin() starts the bus as master. endTransmission() returning 0 means a device answered at that address.

Wire.beginTransmission(address);
if (Wire.endTransmission() == 0) {
  // device present at address
}

Wiring and safe build sequence

  1. Always connect common GND
  2. Check module logic voltage before connection
  3. Keep bus wires short in breadboard prototypes
  4. Do not assume every module is 5 V tolerant
  5. I2C scan demo: module VCC/GND/SDA/SCL to Uno 5 V (if rated), GND, A4, A5
Power rule: switch off before moving wires. Arduino I/O pins are control signals; high-current loads require a driver and suitable external supply.
#include <Wire.h>

void setup() {
  Serial.begin(9600);
  Wire.begin();
  Serial.println("I2C addresses:");
  for (byte address = 1; address < 127; address++) {
    Wire.beginTransmission(address);
    if (Wire.endTransmission() == 0) {
      Serial.print("0x");
      if (address < 16) Serial.print('0');
      Serial.println(address, HEX);
    }
  }
}

void loop() {}

How the code works

  1. The scanner attempts every valid 7-bit address once in setup.
  2. A zero return from endTransmission indicates an acknowledged address.
  3. No printed addresses usually means wiring, power, pull-ups or voltage mismatch.

Test and record evidence

Expected result: Connected I2C devices appear as hexadecimal addresses on Serial.

Practical evidence checklist

Common faults and checks
  • No addresses: check power, GND, SDA/SCL swapped, and pull-ups.
  • Several unexpected addresses may indicate noise or voltage problems.
  • UART upload fails: disconnect anything wired to D0/D1, then try again.
  • SPI device silent: confirm CS pin, idle HIGH on unused CS lines, and shared GND.
  • Confirm 5 V vs 3.3 V module ratings before powering.
Extension challenge: Create a comparison table selecting a bus for a GPS module, an RTC and an SD card.

Check your understanding

Q1. Which bus uses a chip-select line per device?

Show answer

SPI.

Q2. Which bus uses device addresses on two shared wires?

Show answer

I2C.

Q3. Which Uno pins are hardware UART?

Show answer

D0 (RX) and D1 (TX).

Q4. Why cross TX to RX on UART?

Show answer

Each side transmits on TX and listens on RX - they must meet.