← All projects
Wireless Beginner

An IR Remote Controls the ESP32: the VS1838B Receiver and the NEC Protocol

Any old TV remote becomes a wireless keypad. The VS1838B receiver, the IRremote 4.x library, how an NEC frame is built, repeat codes when a key is held — and three LEDs switched from the remote.

Difficulty
Beginner
Time
40 min
Category
Wireless
Updated

About the project

An infrared remote is the cheapest wireless control there is: no Wi-Fi, no pairing, no battery on the receiver side. The VS1838B receiver (or a TSOP38238) filters out the 38 kHz carrier by itself and outputs clean digital pulses, and the IRremote library turns them into key codes. We control three LEDs from the common 21-key "Car MP3" remote.

What you need

  • ESP32 DevKit
  • VS1838B IR receiver (bare or on a module) + any remote
  • 3 LEDs and 3 × 220 Ω resistors
  • The IRremote library, version 4.x

Wiring

Receiver ESP32
OUT (left, looking at the lens) GPIO15
GND (middle) GND
VCC (right) 3V3

LEDs: GPIO25 / 26 / 27 → 220 Ω → LED → GND.

The pinout of VS1838B parts and modules varies, so check yours. Swapping VCC and GND kills the receiver instantly.

The NEC protocol

The remote blinks its LED at 38 kHz, and the receiver outputs LOW while it sees that light. An NEC frame:

 9 ms LOW │ 4.5 ms HIGH │ 32 bits: address, ~address, command, ~command │ stop
 bit "0": 562 µs LOW + 562 µs HIGH        bit "1": 562 µs LOW + 1687 µs HIGH
  • The address selects the device (often 0x00 on cheap remotes), the command selects the key.
  • The inverted copies (~address, ~command) are a check, so interference does not become a wrong command.
  • Holding a key: instead of repeating the frame, the remote sends a short repeat code every 108 ms. IRremote marks it with the IRDATA_FLAGS_IS_REPEAT flag.

Code

// IR remote (NEC, 21-key "Car MP3") → three LEDs. Library: IRremote 4.x
#include <IRremote.hpp>

const int IR_PIN = 15;
const int LEDS[] = {25, 26, 27};
bool state[3] = {false, false, false};

void setup() {
  Serial.begin(115200);
  for (int i = 0; i < 3; i++) pinMode(LEDS[i], OUTPUT);
  IrReceiver.begin(IR_PIN, ENABLE_LED_FEEDBACK);
  Serial.println("Press 1, 2, 3 or 0 on the remote");
}

void toggle(int i) {
  state[i] = !state[i];
  digitalWrite(LEDS[i], state[i]);
}

void loop() {
  if (!IrReceiver.decode()) return;
  IrReceiver.printIRResultShort(&Serial);   // protocol, address and command to the port
  // a held key sends repeat codes: react only to the first press
  if (!(IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT)) {
    switch (IrReceiver.decodedIRData.command) {
      case 0x0C: toggle(0); break;   // 1
      case 0x18: toggle(1); break;   // 2
      case 0x5E: toggle(2); break;   // 3
      case 0x16:                     // 0 — all off
        for (int i = 0; i < 3; i++) { state[i] = false; digitalWrite(LEDS[i], LOW); }
        break;
    }
  }
  IrReceiver.resume();   // ready for the next code
}

Finding your remote's codes

Leave only printIRResultShort(&Serial) and resume() in loop(), press the keys and write down the Command=0x… values. Then put them into the switch.

Older tutorials use the IRremote 2.x API (IRrecv irrecv(pin); decode_results results; results.value) with codes like 0xFFA25D. That is the same frame, just read with the bits in reverse order. Version 4.x splits it into address and command.

Good to know

  • Sunlight and energy-saving lamps produce IR noise. Keep the receiver in the shade and add 100 nF between VCC and GND right at it.
  • Don't forget resume(), or no further codes are received.
  • You can transmit too: a 940 nm IR LED driven through a transistor plus IrSender.sendNEC(address, command, 0) turns the ESP32 into a remote for an air conditioner or a TV.