To control a relay with an Arduino, you need a relay module with an optoisolator and a driver transistor, wired to a digital GPIO pin capable of sourcing 20mA. The Arduino pin sends a 5V logic signal to the module's optoisolator, which safely isolates the low-voltage microcontroller from the high-voltage switching circuit while triggering the internal transistor to energize the relay coil.
Project Overview & Hardware Spec Sheet
Estimated Time: 45 minutes
Target Board Variant: Arduino Uno R3 (ATmega328P)
Building a reliable Arduino relay control circuit requires matching the coil voltage to your available power supply and ensuring the GPIO pin isn't overloaded. Below is the exact bill of materials for a standard 5V switching setup.
| Component | Exact Variant / Model | Specs & Notes | Est. Cost |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 | ATmega328P, 5V logic, 20mA max per GPIO | $25.00 |
| Relay Module | SRD-05VDC-SL-C | 5V coil, 10A @ 120VAC, optoisolated | $3.50 |
| Wire (Low Voltage) | 22 AWG Stranded | Pre-tinned, flexible for breadboards | $8.00 |
| Wire (Mains Load) | 14 AWG THHN | Rated for 15A/120VAC branch circuits | $1.00/ft |
| Power Supply | 5V 2A USB Adapter | Provides 1000mA+ to prevent brownouts | $10.00 |
Pin Mapping & Mains Wiring Steps
Before wiring, understand that most 5V relay modules are active-LOW. This means the relay energizes when the input pin is pulled to GND (0V), and de-energizes when it receives 5V (HIGH).
| Arduino Uno R3 Pin | Relay Module Pin | Function |
|---|---|---|
| Digital 8 | IN (Signal) | Logic control (Active LOW) |
| 5V | VCC | Powers the optoisolator LED |
| GND | GND | Common ground reference |
- Wire the Low-Voltage Side: Connect Arduino 5V to the module's VCC, Arduino GND to the module's GND, and Digital Pin 8 to the IN pin.
- Check the Jumper: Leave the blue jumper cap connecting VCC and JD-VCC in place for basic single-module use. (Remove it only if powering the coil from a separate 5V supply for heavy isolation).
- Wire the High-Voltage Load: Cut the hot (black/brown) wire of your AC load cord. Strip 1/2 inch of insulation.
- Connect to Relay Contacts: Insert one cut end into the Common (COM) terminal and the other into the Normally Open (NO) terminal. Tighten the screw terminals to at least 0.5 Nm torque to prevent arcing.
- Verify: Tug gently on the wires to ensure they are seated beneath the terminal clamp plate, not just pinched by the screw head.
Complete Arduino Relay Control Code
This code targets the Arduino Uno R3. It includes serial debugging, state validation, and non-blocking timing using millis() instead of delay() to keep the microcontroller responsive.
// Target: Arduino Uno R3 (ATmega328P)
// Arduino Relay Control with Error Handling & Non-blocking Timing
#define RELAY_PIN 8
#define SERIAL_BAUD 9600
#define RELAY_ON LOW // Active LOW module
#define RELAY_OFF HIGH
unsigned long previousMillis = 0;
const long interval = 5000; // 5-second toggle interval
bool relayState = false;
void setup() {
Serial.begin(SERIAL_BAUD);
// Wait for serial port to connect (useful for debugging)
while (!Serial && millis() < 3000) {
; // Wait up to 3 seconds
}
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, RELAY_OFF); // Ensure relay starts OFF
Serial.println("System Initialized. Relay is OFF.");
}
void loop() {
unsigned long currentMillis = millis();
// Non-blocking timer for automatic toggling
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
toggleRelay();
}
// Manual override via Serial Monitor
if (Serial.available() > 0) {
char command = Serial.read();
if (command == '1') {
setRelay(true);
} else if (command == '0') {
setRelay(false);
}
}
}
void toggleRelay() {
setRelay(!relayState);
}
void setRelay(bool state) {
relayState = state;
int pinValue = state ? RELAY_ON : RELAY_OFF;
digitalWrite(RELAY_PIN, pinValue);
// Error handling: Verify pin state readback
int readback = digitalRead(RELAY_PIN);
if (readback != pinValue) {
Serial.print("ERROR: Pin state mismatch! Expected ");
Serial.print(pinValue);
Serial.print(", Read ");
Serial.println(readback);
} else {
Serial.print("Relay switched ");
Serial.println(state ? "ON" : "OFF");
}
}
Debugging: First Three Things to Check When It Fails
When your relay refuses to click or the Arduino behaves erratically, don't start rewriting code. Hardware and power delivery cause 90% of relay failures. Check these three items first:
- The Optoisolator Jumper (JD-VCC vs VCC): If the relay LED lights up but you don't hear a click, the coil isn't getting enough current. If you removed the jumper to use an external power supply but forgot to connect the external 5V to JD-VCC, the coil circuit is open. Replace the jumper for single-supply setups.
- Power Brownout from USB Limits: A standard PC USB port supplies 500mA. The Arduino Uno voltage regulator and the relay coil combined can draw 300mA-400mA. If the coil engages and the Arduino instantly resets, you are tripping the USB overcurrent protection. Switch to a dedicated 5V 2A wall adapter plugged into the Arduino's DC barrel jack.
- Compilation Error:
'RELAY_PIN' was not declared in this scope: If the IDE throws this exact error string during compilation, it means the compiler doesn't recognize your pin variable.- Cause 1: You forgot the
#define RELAY_PIN 8at the top of the sketch. - Cause 2: You typed
digitalWrite(Relay_Pin, HIGH)in the loop. C++ is case-sensitive; it must match the definition exactly.
- Cause 1: You forgot the
For deeper component-level theory on driving inductive loads, refer to the SparkFun Relay Tutorial and the official Arduino digitalWrite documentation.
Extending and Simplifying the Build
Once you have basic mechanical relay control working, you will quickly hit the physical limitations of the SRD-05VDC-SL-C: it's loud, the contacts degrade over time when switching high currents, and it suffers from contact bounce.
How to Simplify (Solid State Relays):
Swap the mechanical module for a Solid State Relay (SSR) like the Omron G3MB-202P. SSRs use a TRIAC or MOSFET to switch the load silently, with zero mechanical wear and built-in zero-crossing detection to reduce electromagnetic interference (EMI). Wiring is identical (DC+ to 5V, DC- to GND, CH1 to GPIO), but you eliminate the flyback diode concerns and acoustic noise entirely. Note: SSRs generate heat and require a heatsink for loads above 1A.
How to Extend (Multi-Channel Control):
If you need to control 8 or 16 relays for home automation, you will run out of Arduino GPIO pins. Instead of using an Arduino Mega, wire a 74HC595 Shift Register to your Uno. This allows you to control 8 relays using only 3 Arduino pins (Data, Clock, Latch). You cascade multiple shift registers to scale up to dozens of channels without changing the microcontroller.
Arduino Relay Control FAQ
Can I power a 5V relay module directly from the Arduino Uno 5V pin?
Yes, but with strict limits. The Arduino Uno's onboard 5V regulator can safely supply about 400mA to 500mA total (depending on input voltage and heat dissipation). A single 5V relay coil draws roughly 70mA to 90mA. You can safely power one or two relay modules from the 5V pin. If you use a 4-channel or 8-channel board, you must power the JD-VCC rail from a separate external 5V power supply to prevent overheating the Arduino's voltage regulator.
Why does my Arduino reset every time the relay switches?
This is almost always caused by a voltage brownout or inductive kickback. When the relay coil de-energizes, the collapsing magnetic field generates a high-voltage reverse spike (back-EMF). If your relay module lacks a flyback diode (or if you wired a raw relay without one), this spike couples back into the Arduino's ground plane, resetting the microcontroller. Ensure you are using a module with a built-in flyback diode (like the blue SRD-05VDC-SL-C modules) and that your power supply can handle the startup inrush current.
What is the difference between normally open (NO) and normally closed (NC) relay contacts?
Normally Open (NO) means the circuit is broken (off) when the relay coil is unpowered, and closes (turns on) when energized. This is the safest choice for heaters, lights, and alarms. Normally Closed (NC) means the circuit is complete (on) when unpowered, and breaks (turns off) when energized. Use NC for fail-safe applications, like emergency stop circuits or magnetic locks, where a loss of Arduino power should default the device to a safe state.
How do I control a 12V relay with a 5V Arduino?
You cannot connect a 12V relay coil directly to an Arduino GPIO pin; it will destroy the ATmega328P chip. You must use a 12V power supply for the relay coil and an NPN transistor (like a 2N2222) or a MOSFET (like an IRLZ44N) as a switch. The Arduino 5V GPIO pin connects to the transistor's base/gate through a current-limiting resistor, and the transistor switches the 12V ground path for the relay coil. Alternatively, buy a 12V relay module with an integrated optoisolator and driver transistor, allowing you to control it safely with a 5V logic signal.






