Log #67 · Oct 15, 2026
How to Use an IR Remote and Receiver with Arduino
Read any TV-style infrared remote with a VS1838B or TSOP receiver, find the code of each button, and use them to switch LEDs or relays. Wiring, IRremote library code and troubleshooting.
The small black-domed IR receiver in most Arduino kits can read almost any remote control: the credit-card remote from the kit, an old TV remote or an air-conditioner remote. With a few lines of code you can turn lights on and off, steer a robot or control a fan from across the room.
How IR remotes work
The remote has an infrared LED that flashes invisible light in a pattern. To avoid confusion with sunlight and lamps, the flashes are modulated at about 38 kHz: the LED blinks 38,000 times per second during each "on" pulse. The receiver module contains a photodiode, an amplifier and a filter tuned to 38 kHz, so it ignores steady light and outputs a clean digital signal: LOW while it sees 38 kHz bursts, HIGH otherwise.
The pattern of pulses encodes a protocol (NEC is the most common on cheap remotes), an address and a command, one per button. The Arduino library decodes all of that for you.
Wiring
| Receiver pin | Arduino |
|---|---|
| OUT (S, signal) | pin 2 |
| GND (−) | GND |
| VCC (+) | 5 V |
Check the pin order on your part. On a bare VS1838B, facing the dome, it is usually OUT, GND, VCC from left to right. On three-pin modules (KY-022) it's often S, + (middle), −, but some boards use −, +, S, so follow the labels printed on your board. Wiring VCC and GND backwards can destroy the receiver in seconds, and it gets hot.
For the example below, add three LEDs on pins 8, 9 and 10, each with a 220 Ω resistor (see choosing a resistor for an LED).
Install the library
In the Library Manager, search IRremote and install the one by shirriff, z3t0, ArminJo. This guide uses version 4.x, which changed the code style compared with old tutorials. If you copy an old sketch with IRrecv irrecv(...) and results.value, it is deprecated on the new version and gives different code values, so rewrite it in the new style shown here.
Step 1: read your remote's codes
#include <IRremote.hpp>
const int IR_PIN = 2;
void setup() {
Serial.begin(9600);
IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK); // built-in LED blinks on signals
Serial.println("Press buttons on the remote...");
}
void loop() {
if (IrReceiver.decode()) {
IrReceiver.printIRResultShort(&Serial); // protocol, address, command
IrReceiver.resume(); // ready for the next one
}
}
Open the Serial Monitor at 9600 baud and press each button. You'll see lines like:
Protocol=NEC Address=0x0 Command=0x45 Raw-Data=0xBA45FF00 32 bits LSB first
Write down the Command value for each button you want to use. Holding a button down usually sends repeat frames, shown with a "Repeat" flag.
Step 2: control things with the buttons
Replace the three command values with the ones from your remote:
#include <IRremote.hpp>
const int IR_PIN = 2;
const int LED_PINS[] = {8, 9, 10};
// Commands from step 1 (these are typical for the kit remote: 1, 2, 3)
const uint8_t BTN_1 = 0x0C;
const uint8_t BTN_2 = 0x18;
const uint8_t BTN_3 = 0x5E;
bool ledState[3] = {false, false, false};
void toggle(int i) {
ledState[i] = !ledState[i];
digitalWrite(LED_PINS[i], ledState[i] ? HIGH : LOW);
}
void setup() {
Serial.begin(9600);
for (int i = 0; i < 3; i++) pinMode(LED_PINS[i], OUTPUT);
IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK);
}
void loop() {
if (!IrReceiver.decode()) return;
bool isRepeat = IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT;
uint8_t cmd = IrReceiver.decodedIRData.command;
IrReceiver.resume();
if (isRepeat) return; // ignore held-down repeats for toggles
if (cmd == BTN_1) toggle(0);
else if (cmd == BTN_2) toggle(1);
else if (cmd == BTN_3) toggle(2);
else {
Serial.print("Unknown command 0x");
Serial.println(cmd, HEX);
}
}
Ignoring repeats keeps a toggle from flickering on and off while you hold the button. For something like volume or motor speed, you might want to use the repeats instead, so holding the button keeps changing the value.
To switch a lamp or anything on mains power, drive a relay module from one of the pins instead of an LED, and follow its safety rules.
Range and reliability
- Typical range is 5–10 m in a room, less in bright sunlight.
- Some LED and fluorescent lamps flicker in a way that confuses the receiver. If you get random codes, shade the receiver or move it.
- A 100 Ω resistor in series with VCC and a 4.7–10 µF capacitor from VCC to GND near the receiver filter supply noise, the same circuit used inside TVs. Many modules already have it.
- The remote and receiver must match the carrier frequency. 38 kHz is by far the most common; a 36 or 40 kHz remote usually still works at shorter range.
Conflicts to know about
On the Uno and Nano, the IRremote library uses Timer2, which is also used by tone() and by PWM on pins 3 and 11. If you need a buzzer with IR, use a buzzer that beeps on its own (active buzzer) with digitalWrite(), or check the library docs for selecting another timer. The Servo library uses Timer1, so servos and IR work together.
Troubleshooting
- Nothing prints: check the pin order and that OUT goes to pin 2. The built-in LED should flicker when you press a button.
- Receiver gets hot: VCC and GND are reversed. Unplug immediately.
- Old sketch gives warnings or strange codes: it was written for IRremote 2.x. Use the new
IrReceiverstyle shown here. - Codes are different every press: you're seeing "UNKNOWN" protocol or noise. Move closer, shade the receiver, and try another remote.
— TheSolderBench · found a mistake? tell me