The standard Arduino 5V relay module—typically built around the Songle SRD-05VDC-SL-C—is the most common bridge between low-voltage microcontroller logic and high-voltage AC or DC loads. However, cheap manufacturing tolerances, misunderstood optocoupler isolation, and improper pin mappings lead to frequent bench failures. This guide provides the exact wiring, non-blocking control code, and hardware debugging steps to get your 1-channel 5V relay module switching reliably.
Parts List & Hardware Specifications
Before wiring, verify your exact module variant. The market is flooded with 3.3V and 5V coils that look identical but will fail to trigger or burn out if mismatched with your microcontroller's logic levels.
| Component | Exact Variant / Model | Key Specification | Est. Price (2026) |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 or R4 Minima | 5V logic output, 20mA max per pin | $27.00 |
| Relay Module | 1-Channel 5V with Optocoupler | SRD-05VDC-SL-C, 10A @ 120VAC | $2.50 |
| Logic Wiring | 22 AWG Solid Core (Dupont) | Fits standard 0.1" breadboard headers | $5.00 / spool |
| Load Wiring | 18 AWG Stranded THHN | Rated for 120VAC / 10A continuous | $0.50 / ft |
Pin Mapping and Mains Wiring Procedure
The logic side of the module uses a standard 3-pin header, while the load side uses a 3-pin screw terminal block (COM, NO, NC). Below is the exact pin mapping for an Arduino Uno R3.
| Module Pin | Arduino Uno R3 Pin | Function |
|---|---|---|
| VCC | 5V | Powers the relay coil and optocoupler LED |
| GND | GND | Common ground reference |
| IN | Digital Pin 8 | Trigger signal (Active LOW on most modules) |
- Connect Logic Ground: Run a 22 AWG jumper from the Arduino GND to the relay module GND.
- Connect Logic Power: Run a jumper from the Arduino 5V pin to the module VCC. Note: Do not use the 3.3V pin; the 5V coil will chatter or fail to pull in.
- Connect Trigger: Run a jumper from Arduino Digital Pin 8 to the module IN pin.
- Wire the Load (Normally Open): Strip 1/4" of insulation from your 18 AWG load wires. Insert the AC Hot (Line) wire into the COM terminal and tighten the screw. Insert the wire leading to your appliance into the NO (Normally Open) terminal.
- Verify Torque: Tug gently on the load wires. A loose screw terminal on a 10A AC load will arc, generate heat, and melt the plastic terminal block.
Compilable Control Code (Arduino Uno R3 / R4)
This code targets the Arduino Uno R3 and Uno R4 Minima. It avoids the blocking delay() function, using a non-blocking timer to toggle the relay, and includes a serial command parser with error handling for manual overrides.
/*
* Target Board: Arduino Uno R3 / Uno R4 Minima
* Module: 1-Channel 5V Relay (Active LOW trigger)
* Author: ElectricalFlux Bench Code
*/
// --- PIN DEFINITIONS ---
#define RELAY_PIN 8
#define STATUS_LED LED_BUILTIN
// --- TIMING CONSTANTS ---
const unsigned long TOGGLE_INTERVAL = 5000; // 5 seconds
// --- STATE VARIABLES ---
bool relayState = false;
unsigned long previousMillis = 0;
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 2500); // Wait for serial on native USB boards
pinMode(RELAY_PIN, OUTPUT);
pinMode(STATUS_LED, OUTPUT);
// Initialize relay to OFF state (Active LOW means HIGH = OFF)
digitalWrite(RELAY_PIN, HIGH);
digitalWrite(STATUS_LED, LOW);
Serial.println("SYS: Relay controller initialized. Send 'ON' or 'OFF' to override.");
}
void loop() {
handleSerialCommands();
handleAutoToggle();
}
void handleAutoToggle() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= TOGGLE_INTERVAL) {
previousMillis = currentMillis;
setRelayState(!relayState);
}
}
void handleSerialCommands() {
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
cmd.toUpperCase();
if (cmd == "ON") {
setRelayState(true);
previousMillis = millis(); // Reset auto-timer
} else if (cmd == "OFF") {
setRelayState(false);
previousMillis = millis();
} else {
// Exact error string for debugging invalid serial inputs
Serial.print("ERR: RELAY_CMD_INVALID -> '");
Serial.print(cmd);
Serial.println("'. Expected 'ON' or 'OFF'.");
}
}
}
void setRelayState(bool state) {
relayState = state;
if (relayState) {
digitalWrite(RELAY_PIN, LOW); // Active LOW triggers the optocoupler
digitalWrite(STATUS_LED, HIGH);
Serial.println("STATE: RELAY_ENGAGED");
} else {
digitalWrite(RELAY_PIN, HIGH); // HIGH releases the coil
digitalWrite(STATUS_LED, LOW);
Serial.println("STATE: RELAY_DISENGAGED");
}
}
Debugging: First Three Checks and Common Failures
When a relay circuit fails, it usually presents as either a software compilation error, a serial logic error, or the dreaded "click-no-switch" hardware fault. Here is how to isolate the issue.
1. The First Three Things to Check
- VCC vs. Logic Level Mismatch: If the relay clicks but the microcontroller resets, your USB port cannot supply the ~75mA inrush current the coil demands. Power the Arduino via the barrel jack (7-12V) or use a separate 5V buck converter for the relay VCC.
- Trigger Polarity (Active LOW vs HIGH): 95% of 5V relay modules with optocouplers are Active LOW. Sending a
HIGHsignal turns them off. If your relay is engaged on boot, your pin initialization is inverted. - COM/NO/NC Terminal Miswiring: If the relay clicks audibly but the load never powers on, you have likely wired the load into the NC (Normally Closed) terminal instead of NO, or the screw terminal is biting onto the wire insulation instead of the bare copper.
2. Resolving the "ERR: RELAY_CMD_INVALID" Serial Error
If you are using the serial parser above and see ERR: RELAY_CMD_INVALID -> 'ON '. Expected 'ON' or 'OFF'. in your monitor, the ranked causes are:
- Cause A (Most Likely): Your serial terminal is sending a Carriage Return + Line Feed (
\r\n) and thetrim()function failed to catch a hidden unicode character. Fix: Ensure your IDE serial monitor is set to "Newline" only, not "Both NL & CR". - Cause B: Baud rate mismatch. The code initializes at
115200. If your monitor is at9600, the string arrives as garbled bytes.
3. Resolving Compiler Error: error: 'RELAY_PIN' was not declared in this scope
This exact error string appears when users copy the loop() logic into an existing sketch without the header definitions.
Fix: Ensure the #define RELAY_PIN 8 block is at the very top of your sketch, before void setup(). Never hardcode pin numbers inside the digitalWrite() functions; always use macros for single-point-of-change debugging.
Extending and Simplifying the Build
Extending: The JD-VCC Jumper on Multi-Channel Modules
If you scale this build to a 4-channel or 8-channel relay module, you will notice a 3-pin header with a jumper cap labeled JD-VCC. Most beginner tutorials leave this jumper in place, which defeats the purpose of the optocoupler.
To maintain true galvanic isolation between your microcontroller and the high-voltage relay coils:
- Remove the JD-VCC jumper cap.
- Connect the module's JD-VCC pin to an external 5V power supply.
- Connect the module's GND to the external supply GND (do not connect it to the Arduino GND).
- Connect the Arduino 5V to the module's VCC pin (this only powers the optocoupler LEDs, drawing ~2mA per channel).
This prevents high-voltage transients from the relay coils backfeeding into your Arduino's 5V rail and destroying the ATmega328P or R4 Renesas chip.
Simplifying: Ditch the Relay for DC Loads
If your load is strictly DC (e.g., a 12V LED strip, a 24V solenoid, or a 12V water pump) and draws under 30A, a mechanical relay is the wrong tool. It introduces acoustic noise, contact bounce, and eventual mechanical wear.
The Fix: Replace the relay module with a logic-level N-channel MOSFET like the IRLZ44N. It switches silently at PWM frequencies up to 20kHz, requires only a 100-ohm gate resistor from your Arduino pin, and costs roughly $1.50. Just remember to add a flyback diode (1N4007) across inductive DC loads like pumps and solenoids to prevent voltage spikes from destroying the MOSFET.
Frequently Asked Questions
Can I power the Arduino 5V relay module directly from an ESP32?
Not safely without a level shifter or transistor. The ESP32 operates at 3.3V logic. While a 3.3V signal might barely trigger the PC817 optocoupler inside a 5V module, it operates outside the guaranteed datasheet margins, leading to intermittent triggering. Furthermore, the ESP32's 3.3V regulator cannot supply the 75mA required by the 5V relay coil. You must use a dedicated 5V supply for the relay VCC and a 3.3V-to-5V level shifter (or a simple 2N2222 NPN transistor circuit) for the IN pin.
What is the maximum switching current for the SRD-05VDC-SL-C relay?
The Songle SRD-05VDC-SL-C is stamped with "10A 120VAC / 10A 24VDC". However, this is a peak resistive load rating. For inductive loads (motors, compressors, transformers), you must apply a derating factor of at least 50%. If you are switching a 120V AC window fan or a fridge compressor, keep the continuous draw under 5A to prevent the internal contacts from welding shut due to inrush current arcing.
Why does my relay module buzz or chatter rapidly instead of clicking solidly?
Rapid chatter indicates the coil is receiving insufficient current to fully pull in the armature, causing the internal switch to bounce. This is almost always caused by powering the module's VCC from the Arduino's 3.3V pin, or from a USB hub that is current-limiting the 5V rail to 500mA while the microcontroller and other sensors are already drawing 400mA. Measure the voltage at the module's VCC and GND pins with a multimeter while the relay is trying to engage; if it drops below 4.5V, you need a heavier power supply.






