This one is about the wire, not the chip. Nothing below changes with the board you picked, which is why the chip and language switches are not on it. They come back on the ESP32 pages this one sits underneath.
IR remote codes
An infrared remote is a one-way serial link carried on light, flashed at 38 kHz so the receiver can tell it apart from the sun. By the time it reaches your pin the flashing is gone, and what is left is an ordinary logic signal you can time.
The pin idles high and dips low while light is arriving. Press a button, then put a window behind the sensor.
Two signals, and only one reaches your code
The remote does not simply light its LED. It flashes it on and off 38,000 times a second and switches that flashing on and off in a pattern. The carrier is what makes the signal findable: a TSOP-style receiver contains a filter tuned to 38 kHz, so daylight, incandescent bulbs and most room lighting are ignored.
The receiver then throws the carrier away. Its output pin is a plain digital line, idle high, pulled low while a burst is arriving. Nothing about 38 kHz appears in your program.
NEC, which is what most cheap remotes speak
A frame is a 9 ms burst, a 4.5 ms gap, then 32 bits. Every bit is the same 560 µs burst; the value is in the gap that follows — 560 µs for a 0, 1690 µs for a 1. Pulse distance, not pulse width.
The 32 bits are four bytes: an address, the address inverted, a command, and the command inverted.
The inverted bytes are the error check. IR has no retransmission and no acknowledgement, so the protocol spends half its bandwidth proving the other half arrived. A frame whose command and inverted command disagree is dropped, which is why a remote "stops working near a window" rather than sending wrong commands.
Holding a button down does not resend the frame. It sends a short repeat code — a 9 ms burst and a 2.25 ms gap — about every 110 ms. Libraries surface it as a repeat flag, and code that ignores the flag treats a held button as one press.
Reading one
#include <IRremote.hpp>
#define IR_PIN 15
void setup() {
Serial.begin(115200);
IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK);
}
void loop() {
if (IrReceiver.decode()) {
if (!(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT))
Serial.printf("0x%02X\n", IrReceiver.decodedIRData.command);
IrReceiver.resume(); // without this, nothing decodes again
}
}Run that, press every button, write the numbers down. Remote codes are not standardised across manufacturers and there is no way to look yours up — the capture is the datasheet.
What breaks it
Sunlight and cheap LED bulbs. Both put energy through the 38 kHz filter. Sunlight saturates the receiver so nothing decodes; some LED and CFL bulbs flicker close enough to the carrier to fake bursts. The check bytes catch the result, so the symptom is a button that does nothing.
Line of sight. IR bounces off walls but does not go through them, and range is a few metres.
A blocking delay(). Decoding is interrupt-driven, but a long delay in
loop() means you call decode() after the frame has gone.
Where it sits
One pin, one receiver, one direction, and no wire at all. It is the cheapest way to get a handful of buttons into a project across a room — and it is the last protocol in this chapter that needs a physical path. What follows is the same subject with the ESP32's own drivers under it — I2C, SPI and UART — and after that the wire disappears altogether and the question becomes who speaks first on the network.
Edit this page — content/esp32/ir-remote-codes.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.