The Modern IRremote Arduino Stack (v4.x Migration)
If you are trying to compile an IRremote Arduino sketch copied from a tutorial written before 2022, it will almost certainly fail. The Arduino-IRremote library underwent a massive architectural overhaul in versions 3.0 and 4.0. The old IRrecv class and decode_results struct were deprecated in favor of a memory-efficient singleton object (IrReceiver) and a unified decodedIRData structure. This shift was necessary to support newer protocols and reduce RAM overhead on 8-bit microcontrollers.
This guide targets the Arduino Uno R3 (ATmega328P) and the ubiquitous VS1838B / KY-022 receiver modules. We will cover the exact v4.x syntax, hardware wiring, and how to debug the specific compiler errors that trip up makers migrating old code.
Hardware Spec Sheet & Pin Mapping
The VS1838B is a 38kHz carrier demodulator. It filters out constant IR light (like sunlight) and only passes pulsing signals. However, its internal AGC (Automatic Gain Control) can be easily saturated by incandescent bulbs or direct sunlight, causing dropped packets.
| Component | Exact Variant / Model | Pin / Function | Arduino Uno R3 Connection |
|---|---|---|---|
| Microcontroller | Arduino Uno R3 (ATmega328P) | 5V Output | Receiver VCC |
| IR Receiver | VS1838B (KY-022 Module) | VCC (Left Pin) | 5V |
| IR Receiver | VS1838B (KY-022 Module) | GND (Middle Pin) | GND |
| IR Receiver | VS1838B (KY-022 Module) | OUT / DAT (Right Pin) | Digital Pin 11 |
Step-by-Step: Wiring and Compiling the v4.x Receiver
Follow these steps to wire the hardware and upload a fully compliant v4.x sketch. This code includes serial error handling and overflow detection, which is critical when debugging noisy environments.
- De-energize: Disconnect the Arduino Uno from USB.
- Wire Power: Connect the KY-022 VCC to the Uno 5V pin, and GND to Uno GND.
- Wire Signal: Connect the KY-022 OUT pin to Uno Digital Pin 11.
- Install Library: Open Arduino IDE → Library Manager. Search for
IRremoteby shirriff, crankyoldgit, ArminJo. Install version 4.3.0 or newer. - Upload Code: Copy the complete code block below and upload it to your board.
#include <IRremote.hpp>
// Pin definitions must be explicit for v4.x
const int IR_RECEIVE_PIN = 11;
const int STATUS_LED = 13;
void setup() {
Serial.begin(115200);
// Wait for serial port to connect (useful for debugging)
while (!Serial && millis() < 3000);
Serial.println(F("IRremote v4.x Receiver Initialized"));
// Initialize the receiver.
// ENABLE_LED_FEEDBACK blinks the onboard LED (Pin 13) on signal receipt.
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
pinMode(STATUS_LED, OUTPUT);
}
void loop() {
// Check if a complete IR frame has been received
if (IrReceiver.decode()) {
// Error Handling: Check if the buffer overflowed during reception
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_OVERFLOW) {
Serial.println(F("ERROR: Buffer overflow. Signal too long or interrupts blocked."));
}
// Error Handling: Check for automatic repeat frames (holding down the button)
else if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
Serial.println(F("Repeat frame detected (button held)."));
}
else {
// Print standard protocol, hex value, and bit length
IrReceiver.printIRResultShort(&Serial);
// Example action: Toggle LED on a specific NEC power code
if (IrReceiver.decodedIRData.protocol == NEC &&
IrReceiver.decodedIRData.decodedRawData == 0x18E758A7) {
digitalWrite(STATUS_LED, !digitalRead(STATUS_LED));
Serial.println(F(">> Toggled Status LED"));
}
}
// CRITICAL: Resume receiver to capture the next signal
IrReceiver.resume();
}
}
Debugging: Why is my IRremote sketch throwing errors?
When migrating older code to the modern library, the compiler will throw specific errors. Before diving into code fixes, execute the First Three Checks:
- Hardware Saturation: Is the receiver facing a window or fluorescent light? Cover the sensor with your hand. If random serial output stops, your environment is flooding the 38kHz photodiode with broadband IR noise.
- Library Version: Verify you are not using a forked or outdated 2.x version in your
librariesfolder. Delete old versions and keep only the official 4.x release. - Timer Conflicts: On the ATmega328P, IRremote uses Timer2 by default. If your sketch uses the
tone()function or PWM on Pins 3 and 11, they will conflict and fail. Move your PWM/tone pins to 5, 6, 9, or 10.
Fixing Exact Compiler Errors
If your build fails, look for these exact error strings in the console:
Error 1: error: 'decode_results' does not name a type
- Cause: You declared
decode_results results;globally. This struct was removed in v3.0 to save RAM. - Fix: Delete the declaration entirely. Access data directly via the singleton:
IrReceiver.decodedIRData.decodedRawData.
Error 2: error: no matching function for call to 'IRrecv::decode(decode_results*)'
- Cause: You are passing a pointer to the decode function:
irrecv.decode(&results). - Fix: The modern decode function takes no arguments. Change it to
if (IrReceiver.decode()).
Error 3: warning: 'IR_DEFAULT_FEEDBACK_LED' is deprecated
- Cause: Using old constants for LED feedback configuration.
- Fix: Use
ENABLE_LED_FEEDBACKorDISABLE_LED_FEEDBACKinside theIrReceiver.begin()parameters.
Extending and Simplifying Your IR Build
Depending on your project phase, you may want to strip the code down or scale it up.
To Simplify (Protocol Discovery):
If you just need to map the hex codes of a new remote, do not write custom logic. Open the Arduino IDE Examples menu and load IRremote → IRrecvDump. This built-in sketch automatically identifies the protocol (NEC, RC5, Sony, Samsung), prints the raw array, and generates the exact C++ code snippet you need to transmit that signal later.
To Extend (Adding Transmission):
To transmit IR, wire a 940nm IR LED with a 100Ω current-limiting resistor to Pin 3 (the default TX pin for Timer2 on the Uno). Add IrSender.begin() to your setup, and use IrSender.sendNEC(0x18E758A7, 32) in your loop. Remember that transmitting blocks the microcontroller for the duration of the IR frame (usually 50-100ms).
Frequently Asked Questions
Can I use the IRremote Arduino library on an ESP32 or ESP8266?
Yes, but the hardware mapping changes. The ESP32 uses the RMT (Remote Control) peripheral instead of hardware timers. You can use almost any GPIO pin for RX/TX on the ESP32, but you must avoid pins 6-11 (connected to the SPI flash) and ensure you define the pin before calling IrReceiver.begin(). On the ESP8266, avoid Pin 16 (D0) as it does not support interrupts required for RX timing.
Why does my VS1838B output random noise or continuous LOW signals?
The VS1838B is highly susceptible to electromagnetic interference (EMI) and broadband IR. If you see a continuous stream of random hex codes, check for two things: First, ensure your USB power supply is clean (cheap phone chargers introduce high-frequency switching noise that disrupts the sensor's internal AGC). Second, add a 10µF electrolytic capacitor directly across the VCC and GND pins of the receiver module to filter power rail ripple.
How do I capture and send raw IR signals instead of decoded protocols?
Some proprietary appliances (like certain Dyson fans or older HVAC units) use undocumented protocols that the library cannot decode into a neat hex value. In this case, use the IRrecvDump example to capture the raw timing array (measured in microseconds). You can then re-transmit this exact sequence using the IrSender.sendRaw(rawData, rawDataLength, 38) function, bypassing protocol decoding entirely.
Does the IrReceiver block the main Arduino loop while waiting for a signal?
No. The IrReceiver relies on hardware interrupts tied to Timer2. When a falling edge is detected on Pin 11, the interrupt service routine (ISR) instantly pauses the main loop, records the microsecond timestamp, and returns control. The main loop() only processes the data after the entire frame has been received and validated by the background timer. This allows you to run motors, read sensors, and update displays simultaneously without missing IR packets.
For deeper technical specifications on protocol timing and library architecture, refer to the official Arduino-IRremote GitHub repository and the Adafruit IR Sensor guide.






