If you are building a remote-controlled robot, a smart home blaster, or a media center interface, an arduino sensor ir receiver is your go-to component. But while receiving a 38kHz modulated infrared signal seems trivial, the hardware traps and recent software library overhauls catch thousands of makers off guard every year. This guide cuts through the noise, giving you the exact wiring, the modern V4 C++ code, and the debugging playbook for when your serial monitor spits out compile errors or random gibberish.
The Right Arduino Sensor IR Hardware for the Job
Not all IR sensors are created equal. If you buy a generic "IR sensor" off Amazon or AliExpress, you likely received one of three very different modules. Understanding which one you have prevents hours of debugging.
| Module Type | Core IC | Output | Best Used For |
|---|---|---|---|
| KY-022 Receiver | TSOP1838 / TSOP38238 | Demodulated Digital (LOW on signal) | Decoding TV remotes, NEC/Sony protocols |
| IR Obstacle Avoidance | LM393 Comparator + IR Pair | Digital HIGH/LOW (Pot adjustable) | Line following, proximity detection (2-30cm) |
| Raw IR Photodiode | 940nm Photodiode | Analog Voltage | Flame detection, raw ambient IR measurement |
For decoding remote controls, you must use a demodulating receiver like the KY-022 (which houses a Vishay-style TSOP chip). Remote controls don't just shine a light; they pulse a 38kHz carrier wave. A raw photodiode will just see a blurry mess of ambient light, while the TSOP chip filters out everything except the 38kHz pulses and outputs a clean digital square wave to your microcontroller.
- 1x Arduino Uno R3 (ATmega328P variant, 5V logic)
- 1x KY-022 IR Receiver Module (or bare TSOP38238 with 100Ω resistor and 10µF cap)
- 1x Generic 38kHz IR Remote (NEC protocol standard)
- 3x Male-to-Female or Male-to-Male jumper wires
Wiring the TSOP38238 and KY-022 Modules
Wiring a bare TSOP38238 is straightforward, but the ubiquitous blue KY-022 breakout board has a notorious manufacturing flaw you must verify before applying power.
The KY-022 Silkscreen Trap
On roughly 60% of cheap KY-022 clones, the silkscreen labels for GND and VCC are swapped. If you wire 5V to the pin labeled GND, you will instantly fry the internal TSOP IC. Always verify with a multimeter. Trace the pins from the metal can: Pin 1 is OUT, Pin 2 is GND, Pin 3 is VCC. Match this to the breakout header, ignoring the printed text if it conflicts.
Pin Mapping Table
| KY-022 / TSOP Pin | Arduino Uno R3 Pin | Wire Color (Standard) | Notes |
|---|---|---|---|
| OUT (Signal) | Digital Pin 11 | Yellow / Green | Must be a digital pin capable of interrupts |
| VCC (Power) | 5V | Red | Do NOT use 3.3V on a 5V KY-022 module |
| GND (Ground) | GND | Black | Must share common ground with Arduino |
Complete IRrecvDump Code (Targeting IRremote V4.x)
The following code targets the Arduino Uno R3 (AVR architecture) and uses the modern IRremote V4.x API. Older tutorials use V2 syntax, which will fail to compile on current library versions. This sketch includes robust error handling for buffer overflows and unknown protocols.
/*
* IRremote V4.x Receiver Dump
* Target Board: Arduino Uno R3 (ATmega328P)
* Library: IRremote (Version 4.x via Arduino Library Manager)
*/
#include <IRremote.hpp>
// Pin Definitions
#define IR_RECEIVE_PIN 11
#define LED_STATUS_PIN 13 // Built-in LED for visual feedback
void setup() {
Serial.begin(115200);
while (!Serial); // Wait for serial port on native USB boards
pinMode(LED_STATUS_PIN, OUTPUT);
// Initialize the IR receiver
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
Serial.println(F("IR Receiver Ready. Waiting for signals..."));
}
void loop() {
if (IrReceiver.decode()) {
digitalWrite(LED_STATUS_PIN, HIGH); // Flash LED on receive
// Error Handling: Check for buffer overflow or noise
if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
Serial.println(F("Repeat frame detected."));
} else if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_OVERFLOW) {
Serial.println(F("ERROR: Buffer overflow. Signal too long."));
} else {
// Print the decoded data
Serial.print(F("Protocol: "));
Serial.println(IrReceiver.decodedIRData.protocol);
Serial.print(F("Command: 0x"));
Serial.println(IrReceiver.decodedIRData.command, HEX);
Serial.print(F("Raw Data: 0x"));
Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);
// Print raw timing data for deep debugging
IrReceiver.printIRResultMinimal(&Serial);
Serial.println();
}
digitalWrite(LED_STATUS_PIN, LOW);
IrReceiver.resume(); // CRITICAL: Re-enable receiver for next signal
}
}
Debugging: Fixing the "decode_results" Compile Errors
If you copied code from a 2021 tutorial, your IDE will likely throw a wall of red text. The IRremote library underwent a massive architectural shift between V2 and V4 to support multi-protocol and ESP32 architectures.
The Exact Error Strings
You will typically see one of these two exact error strings in the Arduino IDE console:
error: 'decode_results' does not name a type
error: no matching function for call to 'IRrecv::decode(decode_results*)'
Ranked Causes
- Using V2 Syntax with V4 Library (90% of cases): The old
IRrecvclass anddecode_resultsstruct were deprecated. V4 uses the globalIrReceiverobject and thedecodedIRDatastruct. - Missing the .hpp Extension: V4 requires
#include <IRremote.hpp>instead of the old.hextension to properly handle C++ namespaces and template instantiations for different AVR timers. - Board Timer Conflicts: If you are using an Arduino Leonardo or Micro (ATmega32U4), the default timer used by IRremote conflicts with the
SerialUSB interface. You must define#define IR_USE_AVR_TIMER1before the include statement.
The First Three Things to Check When It Fails
- Check the Library Version: Open Tools > Manage Libraries. Search "IRremote" by shirriff/z3t0. Ensure you are on version 4.x. If you absolutely must use legacy code, roll back to version 2.8.0.
- Verify the KY-022 Pinout with a Multimeter: Set your meter to continuity mode. Touch the black probe to the USB shield (ground) and the red probe to the module pins. Ensure the pin labeled GND actually has continuity to ground before applying 5V.
- Eliminate Ambient IR Noise: Compact Fluorescent (CFL) bulbs and direct sunlight emit massive amounts of 38kHz noise. If your serial monitor is spamming random hex codes without you pressing a button, cup your hand over the sensor or turn off overhead lighting to verify.
Extending and Simplifying Your IR Build
Once you have raw decoding working, you rarely want to dump raw hex data to the serial monitor in a production build. Here is how to adapt the project.
How to Simplify the Build
Strip out the printIRResultMinimal and raw data dumps. Instead, use a simple switch statement on the IrReceiver.decodedIRData.command byte. For NEC protocol remotes, the command byte is highly reliable. For example, if your power button outputs 0x45, your loop simply becomes:
if (IrReceiver.decode()) {
if (IrReceiver.decodedIRData.command == 0x45) {
toggleRelay();
}
IrReceiver.resume();
}
How to Extend the Build (IR Blasting)
To turn your Arduino into an IR blaster (e.g., to control an AC unit), you need an IR transmitter. Do not wire an IR LED directly to an Arduino pin. An Arduino GPIO can only source ~20mA safely, while a 940nm IR LED needs 100mA+ for decent range.
Use a Vishay TSOP38238 compatible setup with a 2N2222 NPN transistor. Wire the Arduino transmit pin (usually Pin 3) through a 1kΩ base resistor to the 2N2222 base. Put the IR LED and a 10Ω current-limiting resistor on the collector side, powered directly from the 5V rail. Use the IrSender.sendNEC() function in the V4 library to blast the codes you captured.
Arduino Sensor IR FAQs
Why is my Arduino sensor IR reading random gibberish when no remote is pressed?
This is almost always caused by ambient light interference. The TSOP38238 is tuned to 38kHz, but sunlight contains a broad spectrum of IR, and older fluorescent ballasts switch at frequencies that can bleed into the 38kHz band. If your serial monitor shows continuous UNKNOWN protocol errors or random short hex codes, move the sensor away from windows and swap CFL bulbs for LEDs. Adding a 10µF electrolytic capacitor directly across the VCC and GND pins of the KY-022 module also drastically reduces power-rail noise that causes false triggers.
Can I use an Arduino sensor IR receiver on an ESP32 instead of an Uno?
Yes, but you must change the pin definitions and understand timer routing. The ESP32 does not use the AVR timer architecture. In the IRremote V4 library, the ESP32 uses the ledc (LED Control) peripheral for PWM generation and hardware timers for receiving. You should assign the receive pin to a GPIO that doesn't conflict with internal flash (avoid GPIO 6-11). GPIO 15 or GPIO 22 are excellent choices for IR receive on the ESP32 DevKit V1. Furthermore, ensure you select the correct ESP32 board variant in the Arduino IDE Boards Manager, or the library will fail to map the hardware timers.
How do I find the exact hex codes for my specific TV remote?
Upload the complete V4 dump code provided in this article to your Arduino. Open the Serial Monitor at 115200 baud. Point your remote at the sensor and press a button. Look at the line that says Command: 0x.... The value next to Command is the specific byte for that button (e.g., Volume Up might be 0x02, Power might be 0x45). Write these down in a spreadsheet. Note that some modern streaming remotes (like FireTV or Roku) use Bluetooth or RF, not IR. If the serial monitor shows absolutely nothing when you press buttons, your remote likely isn't transmitting infrared light—verify by looking at the remote's emitter through a smartphone camera lens while pressing a button; you should see a faint purple flash.






