Difficulty: Beginner-Intermediate | Time: 45 minutes | Target Board: Arduino Uno R3 (ATmega328P)

To switch a 120V AC load using a standard 5V relay module and an Arduino Uno R3, connect the module VCC to the Arduino 5V pin, GND to GND, and the IN pin to a digital GPIO (like D8). Use the Normally Open (NO) contact for standard switching. The module handles the heavy lifting: an onboard optocoupler isolates the logic side, and a transistor drives the 70mA coil current that the ATmega328P cannot safely source on its own.

Spec Sheet: 5V Relay Module vs. Bare Electromechanical Relay

Most hobbyists grab the ubiquitous blue 5V relay module, but understanding how it differs from a bare relay (like the Omron G5V-2) is critical when you move from breadboard prototypes to custom PCBs. The module adds support circuitry that changes your drive requirements.

Parameter 5V Module (SRD-05VDC-SL-C) Bare Relay (Omron G5V-2)
Coil Voltage 5.0V DC nominal 5.0V DC nominal
Coil Current Draw ~70mA (at 5V) ~71mA (at 5V)
GPIO Drive Required <2mA (drives optocoupler LED) ~71mA (requires external BJT/MOSFET)
Flyback Diode Integrated (1N4148 equivalent) Must be added externally
Optoisolation Yes (PC817 optocoupler) No (galvanic isolation via coil only)
Typical Price (2026) $1.50 - $2.50 per unit $3.00 - $4.50 per unit

As noted in the All About Circuits relay guide, the flyback diode is non-negotiable for inductive loads like relay coils. When the coil de-energizes, the collapsing magnetic field generates a high-voltage reverse spike. Without the diode clamping this spike, you will fry the Arduino GPIO pin or the driving transistor.

Parts List and Pin Mapping

This build assumes you are using the most common beginner-friendly hardware stack. If you are using an ESP32 or a 3.3V Arduino (like the Due or Nano 33 IoT), you must use a 3.3V relay module or add a logic-level translator, as 3.3V is often below the forward voltage threshold to trigger the 5V module's optocoupler reliably.

Required Components

  • Microcontroller: Arduino Uno R3 (ATmega328P, 5V logic)
  • Relay Module: Single-Channel 5V Relay Module (Songle SRD-05VDC-SL-C)
  • Wiring: 22 AWG solid core jumper wires (Dupont style)
  • Load (Test): 120V AC Desk Lamp with cut/spliced power cord
  • Connectors: 3-position WAGO 221 lever nuts (for safe mains splicing)

Pin Mapping Table

Relay Module Pin Arduino Uno R3 Pin Wire Color Function / Notes
VCC 5V Red Powers the coil and optocoupler
GND GND Black Common ground reference
IN D8 Yellow Logic trigger (Active LOW)

Wiring the Circuit (Step-by-Step)

MAINS VOLTAGE HAZARD: Working with 120V/240V AC can be fatal. De-energize the circuit at the breaker, verify it is dead with a CAT III multimeter, and use proper terminal blocks or lever nuts. Never leave exposed mains connections on a breadboard. If you are unsure, consult a licensed electrician.
  1. Wire the Low-Voltage Control Side: Connect the red jumper from the Arduino 5V pin to the module VCC. Connect the black jumper from Arduino GND to the module GND. Connect the yellow jumper from Arduino D8 to the module IN pin.
  2. Verify the Logic State: Most 5V relay modules are Active LOW. This means the relay engages when the IN pin is pulled to GND (0V), and disengages when it is HIGH (5V). Set your multimeter to continuity mode to verify the switch states before applying mains power.
  3. Prepare the Mains Load: Unplug the desk lamp. Cut the hot (black) wire of the lamp cord. Strip 1/2 inch of insulation from both cut ends.
  4. Connect to Relay Contacts: Insert one stripped end of the lamp's hot wire into the COM (Common) terminal of the relay module and tighten the screw. Insert the other stripped end into the NO (Normally Open) terminal. Leave the neutral (white) wire continuous and wire-nutted together.
  5. Final Verification: Ensure no stray copper strands are bridging the COM and NO terminals. Plug the lamp into the wall. The lamp should remain OFF until the Arduino triggers the relay.

Compilable Arduino Code with Error Handling

The code below targets the Arduino Uno R3. It uses a non-blocking serial parser to listen for commands, allowing you to integrate this into larger projects without using delay(). It includes strict input validation and error reporting, which is essential when debugging over a serial monitor. For more on serial communication best practices, refer to the Arduino Serial Reference.

// Target: Arduino Uno R3 (ATmega328P)
// Project: Serial-Controlled Relay with Error Handling

#include <Arduino.h>

const uint8_t RELAY_PIN = 8;
const uint32_t BAUD_RATE = 115200;

// Active LOW relay logic states
const uint8_t RELAY_ON = LOW;
const uint8_t RELAY_OFF = HIGH;

void setup() {
  // Configure pin and set to safe OFF state immediately
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, RELAY_OFF); 
  
  Serial.begin(BAUD_RATE);
  Serial.println(F("SYS: Relay Controller Ready."));
  Serial.println(F("SYS: Send 'ON' or 'OFF' followed by Enter."));
}

void loop() {
  if (Serial.available() > 0) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();       // Remove trailing \r or spaces
    cmd.toUpperCase(); // Normalize input

    if (cmd == "ON") {
      digitalWrite(RELAY_PIN, RELAY_ON);
      Serial.println(F("ACK: RELAY_ENGAGED"));
    } 
    else if (cmd == "OFF") {
      digitalWrite(RELAY_PIN, RELAY_OFF);
      Serial.println(F("ACK: RELAY_DISENGAGED"));
    } 
    else if (cmd.length() == 0) {
      // Ignore empty lines caused by double line-endings
    }
    else {
      // Error handling for invalid commands
      Serial.print(F("ERR: INVALID_CMD -> "));
      Serial.println(cmd);
      Serial.println(F("HINT: Accepted commands are 'ON' and 'OFF'."));
    }
  }
}
Pro Tip: If you are powering the Arduino via a USB hub and the relay clicks but the Arduino resets, your USB port is browning out. The 70mA coil inrush current combined with the ATmega's draw can exceed the 500mA limit of unpowered hubs. Use a dedicated 5V 2A wall adapter for the Arduino's barrel jack when switching heavy coils.

Debugging: First Three Things to Check When It Fails

When a relay circuit fails, the issue is rarely the microcontroller itself. It is almost always a power delivery or contact wiring fault. Here are the first three things to check, ranked by frequency of occurrence on the workbench.

1. The "Click but No Switch" (Contacts Wired Wrong)

Symptom: You hear the mechanical click, the module LED turns on, but your 120V lamp stays off (or stays on permanently).
Cause: You wired the load to the NC (Normally Closed) terminal instead of NO (Normally Open), or the COM terminal is loose.
Fix: De-energize the mains. Move the load wire from NC to NO. Verify continuity with a multimeter between COM and NO while manually triggering the module with a jumper wire from GND to IN.

2. The "No Click, LED Stays Dim" (Insufficient Coil Current)

Symptom: The power LED on the relay module glows faintly, but the relay never pulls in. No audible click.
Cause: Voltage drop across the power rails. The optocoupler LED is turning on, but the transistor isn't getting enough base drive to saturate and power the 70mA coil.
Fix: Measure the voltage directly at the module's VCC and GND pins while triggering. If it reads below 4.5V, your power source is sagging. Switch from long, thin jumper wires to thicker 22 AWG or 20 AWG wire, or power the module's VCC from a separate 5V bench supply (sharing a common GND with the Arduino).

3. The "Arduino Resets on Trigger" (Back-EMF Brownout)

Symptom: The relay clicks once, and immediately the Arduino reboots. If you are uploading code, the IDE throws the exact error string: avrdude: stk500_recv(): programmer is not responding.
Cause: Back-EMF from the relay coil collapsing is injecting noise back into the 5V rail, or the initial coil inrush is pulling the USB 5V line below the ATmega16U2 USB-to-Serial chip's brownout threshold (typically ~4.0V).
Fix: Ensure the flyback diode on the module is intact (check with a multimeter in diode mode; it should read ~0.5V forward and OL reverse). Add a 100µF electrolytic capacitor across the module's VCC and GND pins to act as a local energy reservoir during the coil's inrush spike.

Extending and Simplifying the Build

Once you have a single relay working, you will inevitably want to scale the project. Depending on your load type, you should either simplify the hardware or expand the I/O intelligently.

Simplify: Switch to a Logic-Level MOSFET for DC Loads

If you are only switching DC loads (like 12V LED strips, PC fans, or heating elements), do not use a mechanical relay. Relays suffer from contact bounce, mechanical wear, and acoustic noise. Instead, use a logic-level N-channel MOSFET like the IRLZ44N. It can be driven directly from a 5V Arduino GPIO, handles up to 47A continuously with a heatsink, and supports high-frequency PWM for dimming or speed control. According to the SparkFun relay and module tutorial, solid-state switching is vastly superior for DC applications where isolation is already handled by the power supply.

Extend: Use I2C GPIO Expanders for Multi-Channel Modules

If you need to switch 8 or 16 independent AC loads (like in a home automation sprinkler or lighting controller), a standard 8-channel relay module will consume all 8 available digital pins on an Uno R3, leaving none for sensors or switches.
The Fix: Use an MCP23017 I2C GPIO Expander. This chip communicates over just two wires (SDA/SCL) and provides 16 additional digital I/O pins. You can drive the optocoupler inputs of a 16-channel relay module directly from the MCP23017, keeping your Arduino's native pins free for reading temperature sensors or physical pushbuttons.