To interface an infrared receiver with an Arduino, wire a 38kHz demodulating receiver module (like the VS1838B or Vishay TSOP38238) to a digital interrupt pin (typically D2), supply it with filtered 5V, and use the modern IRremote v4.x library to decode incoming pulses. While older tutorials rely on deprecated v2 syntax, modern builds require the updated IrReceiver object model to successfully parse NEC, RC5, and Sony SIRC protocols without throwing compilation errors.
Project Overview & Hardware Selection
The core of any infrared receiver Arduino build is the photodiode and demodulator IC. Raw IR photodiodes output a messy analog waveform, requiring heavy software overhead to decode. Demodulating receivers solve this by using an internal bandpass filter tuned to a specific carrier frequency (usually 38kHz) and an Automatic Gain Control (AGC) circuit to strip the carrier wave, outputting a clean digital 1/0 signal directly to your microcontroller's GPIO.
Recommended Parts List
- Microcontroller: Arduino Uno R3 (ATmega328P) or Arduino Uno R4 Minima (Renesas RA4M1). The code provided targets the standard AVR architecture but is fully compatible with the R4 Minima via the latest IRremote board definitions.
- IR Receiver Module: Vishay TSOP38238 (Highly recommended for noise immunity) or the generic VS1838B (Budget option, prone to AGC saturation under modern LED/CFL lighting).
- Power Filtering: 100Ω through-hole resistor and 4.7µF electrolytic capacitor. Do not skip these; breadboard parasitics and USB regulator noise will cause phantom triggers on the VS1838B.
- IR Remote: Any standard 38kHz NEC or RC5 remote (the cheap 24-key white remotes bundled with Arduino sensor kits use the NEC protocol).
Infrared Protocol Specifications & Receiver Selection
Before writing code, you must know which protocol your remote uses. IR protocols differ in how they encode binary 1s and 0s using pulse-distance or pulse-width modulation. Below is a data-dense reference table of the most common consumer IR protocols you will encounter in embedded projects.
| Protocol | Carrier Freq | Bit Length | Encoding Method | Repeat Mechanism | Typical Application |
|---|---|---|---|---|---|
| NEC | 38 kHz | 32 bits (16 addr + 16 cmd) | Pulse Distance | Special repeat code (108ms) | TVs, cheap Arduino kit remotes, DIY electronics |
| RC5 | 36 kHz | 14 bits | Manchester (Bi-phase) | Toggle bit flips on each press | Philips audio/video, European home automation |
| Sony SIRC | 40 kHz | 12, 15, or 20 bits | Pulse Width | Frame repeated 3x minimum | Sony Bravia TVs, PlayStation controllers, car audio |
| Samsung | 38 kHz | 32 bits | Pulse Distance | Entire frame repeated | Samsung TVs, soundbars, HVAC systems |
| RC6 | 36 kHz | Variable (20+ bits) | Manchester (with leader) | Toggle bit in header | Xbox 360 remotes, modern Windows Media Center |
Wiring the VS1838B to Arduino Uno R3
While many tutorials show a direct 3-wire connection to the Arduino, this is a primary cause of erratic behavior. The internal AGC of the receiver is highly sensitive to power rail noise generated by the Arduino's onboard 5V linear regulator and breadboard trace capacitance. Adding an RC low-pass filter stabilizes the VCC line.
Pin Mapping & Filter Wiring
| Receiver Pin | Function | Arduino Connection | Notes / Filter Components |
|---|---|---|---|
| Pin 1 (OUT) | Digital Signal | Digital Pin 2 (D2) | Use an interrupt-capable pin. D2 is standard on Uno. |
| Pin 2 (GND) | Ground | GND | Connect directly to Arduino GND rail. |
| Pin 3 (VCC) | Power (2.5V - 5.5V) | 5V (via 100Ω Resistor) | Place 100Ω resistor between Arduino 5V and Pin 3. |
| N/A (Filter) | Decoupling | Between Pin 3 and GND | Place 4.7µF capacitor as close to the receiver pins as possible. |
Compilable Code: Decoding NEC and RC5 Signals
The following code utilizes the IRremote v4.x API. It targets the Arduino Uno R3/R4 and includes robust error handling for buffer overflows and unknown protocols. Ensure you have installed the "IRremote" library by shirriff/z3t0 via the Arduino Library Manager (select version 4.2.0 or newer).
#include <IRremote.hpp>
// --- PIN DEFINITIONS ---
#define RECV_PIN 2
#define STATUS_LED_PIN 13 // Built-in LED for visual feedback
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for serial port on Leonardo/Micro/R4
// Initialize the IR receiver with LED feedback enabled
// IRremote v4 uses the IrReceiver object instead of the old IRrecv class
IrReceiver.begin(RECV_PIN, ENABLE_LED_FEEDBACK, STATUS_LED_PIN);
Serial.println(F("IR Receiver Ready. Waiting for 38kHz signals..."));
}
void loop() {
// Check if a complete IR frame has been received
if (IrReceiver.decode()) {
// Check for buffer overflow (signal too long for default buffer)
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_WAS_OVERFLOW) {
Serial.println(F("ERROR: Buffer overflow. Try increasing RAW_BUFFER_LENGTH."));
}
else {
// Print a compact summary of the decoded data to Serial
IrReceiver.printIRResultShort(&Serial);
// Example: Trigger action based on specific NEC command
if (IrReceiver.decodedIRData.protocol == NEC) {
if (IrReceiver.decodedIRData.command == 0x18) {
Serial.println(F(">> Action: Volume Up detected!"));
} else if (IrReceiver.decodedIRData.command == 0x19) {
Serial.println(F(">> Action: Volume Down detected!"));
}
}
// Handle unknown protocols gracefully
if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
Serial.println(F("Unknown protocol. Raw data printed for analysis:"));
IrReceiver.printIRResultRawFormatted(&Serial, true);
}
}
// CRITICAL: Resume receiving to clear the buffer and listen for the next signal
IrReceiver.resume();
}
}
Debugging: Compile Errors and Signal Dropouts
When migrating from older tutorials or dealing with noisy environments, you will inevitably hit roadblocks. Here is the exact decision path for the most common hardware and software failures.
Software: Exact Compile Errors
Error String: error: 'decode_results' was not declared in this scope
Ranked Causes & Fixes:
- API Version Mismatch (95% of cases): You are copying a tutorial from 2018 that uses IRremote v2.x syntax (
IRrecv irrecv(RECV_PIN);anddecode_results results;). The v3/v4 rewrite completely removeddecode_results. Fix: Delete the old code and use theIrReceiver.decodedIRDataobject structure provided in the code block above. - Missing Include: You typed
#include <IRremote.h>instead of#include <IRremote.hpp>. The modern library uses the.hppextension for C++ header compatibility. Fix: Update the include statement.
Error String: error: 'IRrecv' does not name a type
Ranked Causes & Fixes:
- Library Not Installed or Wrong Fork: You have the obsolete "IRremoteESP8266" library installed but are compiling for an AVR Arduino Uno, or the library failed to download. Fix: Open Library Manager, search for "IRremote" by shirriff, and install the latest v4.x release. Check the official GitHub repository for migration guides.
Hardware: The First Three Things to Check When It Fails
If the code compiles but the Serial Monitor outputs random hex codes, FFFFFFFF, or nothing at all, run this hardware checklist:
- Check Power Rail Noise (The Phantom Trigger): If the Serial monitor prints random signals without you pressing a button, your VS1838B is saturating due to AC ripple on the 5V rail. Fix: Install the 100Ω resistor and 4.7µF capacitor as detailed in the wiring table. This is mandatory for generic modules.
- Check Carrier Frequency Mismatch: If the receiver only works when the remote is pressed directly against the sensor dome, you likely have a 36kHz remote (RC5) and a strict 38kHz receiver. Fix: Swap to a Vishay TSOP38238, which has a wider bandpass tolerance, or verify your remote's protocol.
- Check Optical Interference: Modern LED bulbs, CFLs, and direct sunlight emit broadband IR noise that blinds the AGC circuit. Fix: Shield the receiver dome with a piece of dark, IR-passing acrylic (often salvaged from old VCR facias) or move the project away from direct window light.
Extending and Simplifying the Build
Once you have reliable decoding, the next step is integrating the IR receiver into a larger embedded system.
How to Simplify: Raw Dump Mode
If you are dealing with an obscure HVAC remote that uses a proprietary 48-bit protocol, attempting to decode the bits is a waste of time. Simplify the build by switching to Raw Dump and Playback. Use IrReceiver.printIRResultRawFormatted(&Serial, true); to capture the raw microsecond timing array. You can then feed this exact array into IrSender.sendRaw() to clone the remote perfectly without ever knowing the underlying binary logic.
How to Extend: High-Voltage Relay Switching
To control mains-powered devices (like a lamp or fan) based on IR commands, do not wire the Arduino GPIO directly to a mechanical relay coil. The back-EMF will fry your ATmega328P. Instead, extend the build using an N-channel MOSFET (like the IRLZ44N) or a 2N2222 BJT to drive a 5V opto-isolated relay module. Add a 1N4007 flyback diode across the relay coil, and map specific NEC commands in the loop() to toggle the MOSFET gate pin. Always ensure your mains wiring follows local electrical codes and is housed in a proper insulated enclosure.






