When global makers search for a sensor infravermelho arduino setup, they usually land on the ubiquitous KY-022 or a bare VS1838B diode. The direct answer for a reliable 5V build is to use the KY-022 module on Pin 2 of an Arduino Uno R3, paired with the IRremote v4.x library. If you are stepping down to 3.3V logic for an ESP32, abandon the KY-022 and use a TSOP38238 breakout instead to avoid comparator brownouts.

Difficulty: Beginner-Intermediate | Time: 20 Minutes | Board Target: Arduino Uno R3 (ATmega328P)

Choosing the Right IR Hardware for Your Bench

Not all 38kHz IR receivers are created equal. The physical packaging and onboard support components dictate whether a module will work on a 5V Uno or a 3.3V ESP32. The KY-022, for instance, includes a status LED and a current-limiting resistor wired directly to the VCC rail. If you feed a KY-022 with 3.3V, the internal LED won't fire, and the sensor's internal preamplifier may fail to trigger the comparator, resulting in silent drops.

Module Variant Sensor IC VCC Range Carrier Freq Output Logic & Notes
KY-022 VS1838B (Generic) 4.5V - 5.5V 38 kHz Active LOW. Fails on 3.3V rails.
TSOP382 Breakout Vishay TSOP38238 2.5V - 5.5V 38 kHz Active LOW. Excellent noise rejection.
Bare VS1838B VS1838B 2.7V - 5.5V 38 kHz Active LOW. Requires 4.7kΩ pull-up.
OS-Opto OS-38B OS-38B 2.7V - 5.5V 38 kHz Active LOW. Good for tight spaces.
Bench Tip: Compact Fluorescent Lamps (CFLs) and direct sunlight emit massive amounts of broadband IR noise around 940nm. If your serial monitor is spamming random hex codes, the Vishay TSOP38238 has superior automatic gain control (AGC) and optical filters compared to the generic VS1838B found on the KY-022.

Parts List and Pin Mapping

For this build, we are targeting the Arduino Uno R3. The ATmega328P operates at 5V logic, making it perfectly matched to the KY-022. You will need:

  • 1x Arduino Uno R3 (or compatible clone with CH340/ATmega16U2)
  • 1x KY-022 IR Receiver Module (or TSOP382 breakout)
  • 1x Standard IR Remote (NEC or RC5 protocol)
  • 3x Male-to-Female jumper wires (22 AWG)

Pin Mapping Table

The IRremote library relies on hardware interrupts for precise microsecond timing. On the Uno R3, Pins 2 and 3 are the only hardware interrupt pins (INT0 and INT1). We use Pin 2 to leave Pin 3 free for PWM output if you later add an RGB LED.

Arduino Uno R3 Pin KY-022 Module Pin Wire Color (Std) Function
5V VCC (or +) Red Power (Must be 5V for KY-022)
GND GND (or -) Black Common Ground
Pin 2 S (or OUT) Yellow Demodulated IR Data (Active LOW)

Compilable Code: IRremote v4.x with Error Handling

The Arduino-IRremote library underwent a massive API overhaul between v2 and v4. The code below is written strictly for v4.x. It includes explicit pin definitions, overflow checking, and repeat-flag handling to prevent your serial monitor from drowning in duplicate keypresses.

#include <IRremote.hpp>

// --- PIN DEFINITIONS ---
#define IR_RECEIVE_PIN 2
#define STATUS_LED_PIN LED_BUILTIN

void setup() {
  Serial.begin(115200);
  while (!Serial); // Wait for serial port (native USB boards)
  
  // Initialize IRreceiver with LED feedback disabled to save power/noise
  IrReceiver.begin(IR_RECEIVE_PIN, DISABLE_LED_FEEDBACK);
  
  pinMode(STATUS_LED_PIN, OUTPUT);
  digitalWrite(STATUS_LED_PIN, LOW);
  
  Serial.println("IR Receiver Ready. Awaiting 38kHz signal...");
}

void loop() {
  if (IrReceiver.decode()) {
    
    // 1. Check for Buffer Overflow (happens if signal is too long/noisy)
    if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_OVERFLOW) {
      Serial.println("ERROR: IR Buffer Overflow. Signal too long.");
      IrReceiver.resume();
      return;
    }

    // 2. Handle Repeat Codes (e.g., holding down the Volume button)
    if (IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT) {
      Serial.println("REPEAT command received.");
      digitalWrite(STATUS_LED_PIN, HIGH);
      delay(50);
      digitalWrite(STATUS_LED_PIN, LOW);
      IrReceiver.resume();
      return;
    }

    // 3. Process Valid Decoded Data
    Serial.print("Protocol: ");
    Serial.print(IrReceiver.decodedIRData.protocol);
    Serial.print(" | Hex: ");
    Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX);
    
    // Example: Trigger action on a specific NEC code
    if (IrReceiver.decodedIRData.decodedRawData == 0xBA45FF00) {
      Serial.println(">> Power Button Pressed!");
      digitalWrite(STATUS_LED_PIN, !digitalRead(STATUS_LED_PIN));
    }

    // Resume receiving
    IrReceiver.resume();
  }
}

Debugging: Exact Error Strings and the First Three Checks

IR builds are notorious for failing silently or throwing cryptic compiler errors. If your build fails, run through this exact decision path.

The Compiler Errors

Error String: fatal error: IRremote.h: No such file or directory
Cause: You haven't installed the library, or you are using the wrong include name. In v4.x, the preferred header is <IRremote.hpp>, though .h often still maps. Open the Arduino IDE Library Manager, search for 'IRremote' by shirriff/ArminJo, and install the latest 4.x release.

Error String: error: 'class IRrecv' has no member named 'decode'
Cause: You are mixing v2 syntax with the v4 library. In v2, you instantiated an object (IRrecv irrecv(PIN);) and called irrecv.decode(&results). In v4, the library uses a global IrReceiver object. Use the code block provided above.

Hardware Fails: The First Three Things to Check

If the code compiles and uploads, but the Serial Monitor is dead when you press buttons on your remote, check these three physical layer issues:

  1. VCC Rail Mismatch: If you wired a KY-022 to the 3.3V pin on an Uno (or are using an ESP32), the module will not power its internal comparator. Fix: Move the red jumper to the 5V rail. If you must use 3.3V logic, switch to a bare TSOP38238 sensor.
  2. Ambient IR Saturation: Take the board outside or point it at a CFL bulb. If the serial monitor suddenly spams random hex codes, your sensor is saturated by environmental 940nm noise. Fix: Shield the sensor with heat-shrink tubing, or upgrade to a Vishay TSOP module with better optical filtering (SparkFun IR Guide).
  3. Wrong Remote Protocol: The code above prints the raw hex. If your remote uses the RC5 or Sony SIRC protocol, the hex values will look different than NEC. Fix: Rely on IrReceiver.printIRResultShort(&Serial); to let the library auto-format the protocol and command byte, rather than hardcoding raw 32-bit hex strings.

Extending and Simplifying the Build

Once you have raw hex codes printing to the serial monitor, you have two paths forward depending on your project goals.

Simplifying for Quick Prototyping

If you just want to map buttons without writing complex if/else trees, replace the manual hex parsing in the loop() with the built-in formatter:

if (IrReceiver.decode()) {
  IrReceiver.printIRResultShort(&Serial);
  IrReceiver.resume();
}

This outputs a clean string like Protocol=NEC Address=0x0 Command=0x18. You can then map actions purely on the 8-bit Command byte, ignoring the address header.

Extending for Home Automation

To turn this into a practical appliance controller, you need to switch mains voltage. Never wire an Arduino GPIO directly to a relay coil. The back-EMF will fry the ATmega328P. Instead:

  • Add an optocoupler (PC817) or a pre-built 5V Relay Module with an onboard optoisolator.
  • Map specific IR hex commands to toggle the relay GPIO.
  • For WiFi integration, swap the Uno R3 for an ESP32-WROOM-32. Use the attachInterrupt() documentation to verify ESP32 pin compatibility, and push the decoded IR commands to an MQTT broker via the PubSubClient library to integrate with Home Assistant.
Safety Warning: When extending IR control to mains-powered relays (120V/240V AC), always de-energize the circuit, verify dead with a CAT III multimeter, and ensure your relay module is rated for the inductive load of your appliance. Local electrical codes may require a licensed electrician for permanent mains wiring.