To use an IR infrared sensor with an Arduino, you need a 38kHz receiver like the TSOP4838 or a KY-022 breakout, wired to a standard digital pin (e.g., Pin 11 on an Uno R3), and programmed using the modern IRremote library (v4.x) to decode NEC, RC5, or Sony protocols. The direct answer to most wiring failures is a mismatched library version or a reversed VCC/GND silkscreen on cheap breakout boards.

This guide walks through the exact hardware specs, wiring diagrams, and v4.x code required to get your IR receiver decoding remote commands reliably, along with a dedicated debugging section for the most common compiler and hardware errors.

Spec Sheet & Component Selection

Before wiring anything, you need to choose between a bare IR receiver IC and a pre-wired breakout module. Bare sensors require a simple RC filter to stabilize the internal pre-amplifier, while breakouts handle this on the PCB. Below is a data-dense comparison of the most common 38kHz IR receivers on the maker market in 2026.

Table 1: IR Receiver Module Comparison
Component / Module Carrier Freq Supply Voltage Output Type Typical Cost (2026) Best Use Case
TSOP4838 (Bare IC) 38 kHz 2.5V - 5.5V Active Low (Open Drain) $0.85 Custom PCBs, tight spaces, 3.3V logic (ESP32)
VS1838B (Bare IC) 38 kHz 2.7V - 5.5V Active Low $0.40 Budget bulk builds, hobbyist breadboarding
KY-022 (Breakout) 38 kHz 3.3V - 5.0V Active Low (w/ Pull-up) $1.50 Quick prototyping, Arduino starter kits
Adafruit IR Sensor (954) 38 kHz 3.0V - 5.0V Active Low (w/ LED) $5.95 Production prototyping, guaranteed silkscreen accuracy
Bench Tip: If you are using a bare TSOP4838 or VS1838B, you must include a 100Ω series resistor on the VCC line and a 4.7µF decoupling capacitor between VCC and GND. Without this RC filter, the sensor's internal AGC (Automatic Gain Control) will overreact to power supply ripple, causing ghost signals or total deafness to the remote.

Supported IR Protocols

Not all remotes speak the same language. The IRremote library supports dozens, but 90% of consumer electronics use one of these four:

Table 2: Common Consumer IR Protocols
Protocol Bit Length Carrier Freq Lead Time (Header) Common Devices
NEC 32 bits (or 16) 38 kHz 9ms + 4.5ms TVs, LED strips, generic car audio
Sony SIRC 12, 15, or 20 40 kHz 2.4ms + 0.6ms Sony Bravia, PlayStation, older camcorders
RC5 / RC6 14 / 20 bits 36 kHz Toggle bit included Philips, European audio equipment
Samsung 32 bits 38 kHz 4.5ms + 4.5ms Samsung TVs, soundbars, home theater

Pin Mapping & Wiring the IR Receiver

The wiring for this project targets the Arduino Uno R3 (ATmega328P) or the Arduino Nano v3. Both operate at 5V logic, which perfectly matches the TSOP4838 and KY-022 modules. We are using Digital Pin 11, as it avoids the hardware timer conflicts associated with Pins 3 and 9 on the Uno when using the IRremote library's PWM transmit features later.

Wiring Table

KY-022 Breakout Pin Bare TSOP4838 Pin Arduino Uno R3 Pin Notes & Warnings
S (Signal) Pin 1 (OUT) D11 Active LOW. Pulled HIGH internally by Arduino.
+ (VCC) Pin 2 (VS) 5V Warning: Check silkscreen! Cheap clones often swap VCC/GND.
GND Pin 3 (GND) GND Must share common ground with the Arduino.
The KY-022 Silkscreen Trap: Many mass-produced KY-022 modules from third-party marketplaces print the pins as GND | VCC | SIG (left to right), but the actual PCB traces route VCC to the middle pin and GND to the left. Always verify the pins by tracing the copper from the header to the TSOP/VS1838B chip on the board. Pin 2 on the bare sensor is always VCC. If you wire 5V to the ground pin, you will instantly fry the sensor's internal pre-amp.

Step-by-Step Wiring Procedure

  1. De-energize: Unplug the Arduino Uno R3 from the USB cable.
  2. Seat the Module: Insert the KY-022 breakout or bare TSOP4838 into the breadboard. If using the bare IC, place the 100Ω resistor and 4.7µF capacitor across the power rails as per the Vishay application circuit.
  3. Connect Signal: Run a 22 AWG jumper wire from the Signal (S) pin to Arduino Digital Pin 11.
  4. Connect Power: Connect the verified VCC pin to the Arduino 5V rail.
  5. Connect Ground: Connect the GND pin to the Arduino GND rail.
  6. Verify: Use a multimeter in continuity mode to ensure VCC and GND are not shorted before applying power.

Complete Arduino Code for IR Decoding

The code below uses the modern IRremote v4.x API. This is critical: the Arduino Library Manager defaults to v4.x, but 90% of the tutorials on the web still use the deprecated v2.x syntax. This code includes error handling for buffer overflows and unknown protocols, which are common when dealing with cheap universal remotes.

Prerequisite: Install the "IRremote" library by shirriff / ArminJo via the Arduino IDE Library Manager (ensure version 4.x).

/*
 * IR Infrared Sensor Arduino Decoder (IRremote v4.x)
 * Target Board: Arduino Uno R3 / Nano v3 (ATmega328P)
 * Sensor: TSOP4838 or KY-022 (38kHz)
 * Pin: Digital 11
 */

#include 

// --- PIN DEFINITIONS ---
const uint8_t IR_RECEIVE_PIN = 11;
const uint8_t STATUS_LED_PIN = LED_BUILTIN; // Pin 13 on Uno

void setup() {
  // Initialize Serial at 115200 baud for fast data dumping
  Serial.begin(115200);
  while (!Serial); // Wait for serial port on native USB boards (Leo/Micro)
  
  Serial.println(F("IR Receiver Initialized. Waiting for NEC/RC5/Sony signals..."));
  
  // Start the IR receiver. ENABLE_LED_FEEDBACK blinks Pin 13 on signal receipt.
  IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
}

void loop() {
  // Check if a complete IR packet has been received
  if (IrReceiver.decode()) {
    
    // 1. Handle Buffer Overflow (Signal too long or interrupted)
    if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_WAS_OVERFLOW) {
      Serial.println(F("ERROR: Buffer overflow. Try increasing RAW_BUFFER_LENGTH."));
      IrReceiver.resume(); 
      return;
    }

    // 2. Handle Unknown Protocols (e.g., AC units with rolling codes)
    if (IrReceiver.decodedIRData.protocol == UNKNOWN) {
      Serial.print(F("UNKNOWN Protocol. Raw data length: "));
      Serial.println(IrReceiver.decodedIRData.rawDataPtr->rawlen);
      // Print raw timing data for manual reverse-engineering
      IrReceiver.printIRResultRawFormatted(&Serial, true);
    } 
    // 3. Handle Known Protocols (NEC, Sony, etc.)
    else {
      // Print standard summary (Protocol name, Hex command, Bit length)
      IrReceiver.printIRResultShort(&Serial);
      
      // Extract specific data for custom logic
      uint32_t command = IrReceiver.decodedIRData.command;
      uint32_t address = IrReceiver.decodedIRData.address;
      
      Serial.print(F("-> Extracted Command Hex: 0x"));
      Serial.println(command, HEX);
      
      // Example: Trigger action on a specific NEC remote button
      if (IrReceiver.decodedIRData.protocol == NEC && command == 0x18) {
        Serial.println(F("*** POWER BUTTON PRESSED ***"));
        digitalWrite(STATUS_LED_PIN, !digitalRead(STATUS_LED_PIN));
      }
    }

    // CRITICAL: Resume receiving to clear the buffer and catch the next signal
    IrReceiver.resume(); 
  }
}

Debugging: "IRrecv Does Not Name a Type" & Common Failures

When compiling IR sketches, the most frequent roadblock is a compiler error stemming from the transition between IRremote library versions. If you are copying code from a forum post older than 2023, you will likely hit this.

The Exact Error String

error: 'IRrecv' does not name a type; did you mean 'irrecv'?
error: 'irrecv' was not declared in this scope

Ranked Causes & Fixes

  1. Version Mismatch (Most Likely): You installed IRremote v4.x via the Library Manager, but the code uses v2.x syntax (IRrecv irrecv(RECV_PIN);). Fix: Delete the old code and use the v4.x IrReceiver.begin() syntax provided in the code block above.
  2. Missing Header Extension: In v4.x, the include file changed. Fix: Ensure your first line is #include <IRremote.hpp> (with the .hpp), not #include <IRremote.h>.
  3. Timer Conflict on Pin 3/9: If you are using an Uno and try to receive on Pin 3 while simultaneously using the tone() function or Servo library, the hardware timer will collide. Fix: Move the IR receiver to Pin 11.

The First 3 Things to Check When It Fails to Decode

If the code compiles but the Serial Monitor stays blank when you press buttons on your remote, run this hardware checklist:

  • 1. Ambient Light Interference: Direct sunlight and cheap CFL/LED bulbs emit massive amounts of broadband IR noise that blinds the 38kHz AGC. Test: Cup your hand over the sensor to block room light, then press the remote. If it works, you need an IR-pass optical filter or to move away from the window.
  • 2. The 3.3V vs 5V Logic Trap: If you wired a KY-022 to an ESP32 (3.3V logic), the sensor might output a 3.3V HIGH signal, but the ESP32's threshold might be marginal. More importantly, if you powered the KY-022 with 3.3V but are using a 5V Arduino, the output HIGH will only be 3.3V, which the ATmega328P might read as a floating state. Fix: Power the sensor with the same voltage as the microcontroller's logic level.
  • 3. Remote Protocol Mismatch: Some modern TV remotes (especially Samsung and LG) use proprietary or encrypted protocols that don't map to standard NEC/Sony. Fix: Grab a cheap 24-key LED strip remote. These almost universally use standard, unencrypted NEC and are perfect for testing basic hardware functionality.

Extending and Simplifying Your IR Build

Once you have basic decoding working, you will inevitably want to either strip the build down for production or scale it up to control other devices.

How to Simplify the Build

If you are building a permanent IoT device (like an IR-to-MQTT bridge for Home Assistant), drop the Arduino Uno and switch to an ESP32-WROOM-32. The ESP32 handles the IRremoteESP8266 library (a fork optimized for Espressif chips) and allows you to send decoded IR commands over WiFi via MQTT. Furthermore, use a bare TSOP4838 soldered directly to a perfboard rather than a bulky KY-022 breakout to save space and eliminate the unregulated voltage drop across the breakout's cheap LDO.

How to Extend: Building an IR Blaster

To send IR commands (e.g., turning on your AC unit), you need an IR transmitter. Do not wire an IR LED directly to an Arduino GPIO pin. The ATmega328P can only safely source 20mA per pin, but an IR LED needs 100mA pulses to achieve the 5-meter range required to bounce off walls and hit the TV sensor.

The Blaster Circuit:

  • Use a 940nm IR LED (e.g., Vishay TSAL6200).
  • Drive it with an NPN transistor like the 2N2222 or a MOSFET like the 2N7000.
  • Connect the Arduino PWM pin (Pin 3) to the transistor base via a 1kΩ resistor.
  • Place a 10Ω current-limiting resistor in series with the IR LED on the 5V rail. This allows ~150mA pulses, which the LED can handle safely at the 10% duty cycle typical of 38kHz carrier waves.

For deeper protocol analysis and raw timing diagrams, refer to the official Arduino-IRremote GitHub repository and the Adafruit IR Sensor overview. Understanding the exact microsecond timing of the NEC header pulse is the key to moving from simply copying hex codes to writing robust, universal IR translators.