IR remote/The receiver/04. Your first key code
The receiver · 04 of 11

Your first key code

Three wires and one library, and every button on the remote prints its protocol, its address and its command. Keep this sketch: nothing you build with the sender works until it has told you what your remote sends.

Three wires

Three wires to the receiver
Your board
Wires
3
VCC to
5V
SIGNAL to
D2
GND to GND, VCC to 5V, SIGNAL to D2. D2 is any digital pin. On an Uno the library samples it with Timer2, which costs analogWrite on pins 3 and 11 while receiving. SIGNAL idles at whatever VCC is, through 30 kΩ inside the chip, so VCC is your board's own logic voltage.

GND to GND, VCC to your board's logic supply, SIGNAL to a digital pin, NC to nothing. The receive pin is the same in every sketch in this book: D2 on an Uno, GPIO 23 on an ESP32, GPIO 9 on an ESP32-S3, GP16 on a Pico. Any other input pin works too.

The sketch

Three library calls do the work.

IrReceiver.begin(pin, DISABLE_LED_FEEDBACK) starts a timer that samples the pin every 50 microseconds and records how long it stays low and high.

IrReceiver.decode() returns true once a whole frame has arrived and been matched against every decoder the library has. It never waits.

IrReceiver.resume() hands the buffer back. Until you call it the library looks at nothing else, and nothing says so: forget it and the sketch decodes one press and then looks dead.

What you should see

Open the Serial Monitor at 115200 and press every button in turn:

NEC  address=0x4  command=0x16  first time, 1 so far
NEC  address=0x4  command=0x17  first time, 2 so far
NEC  address=0x4  command=0x17
[repeat]
[repeat]

Your numbers will differ; that is the point of the next chapter but one. The address is the same for every button on one remote. The command changes per button, and it is the number your project will act on. Holding a button gives [repeat] every 110 ms instead of another code.

Write them down

Press all seventeen buttons and copy the address and command of the ones you care about into a comment. Be the remote and one button, one job need them, and they exist nowhere except in the remote in your hand.

The code

Prints one line per button press and counts how many different codes it has seen. Change IR_RX_PIN to the pin SIGNAL is on and nothing else. The remote in the kit has seventeen buttons, so a full pass ends at 17.

ir_key_codes.ino
/*
  IR Receiver - key codes                                TK15 / /p/tk15

  Wiring. Count from the square pad on the TinkerBlock board, parts
  up, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
              (SIGNAL idles at VCC, so match your board)
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> D2 on an Uno, GPIO 23 on an ESP32, GPIO 9 on an
              ESP32-S3, GP16 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. Arduino Uno
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    Tools > Manage Libraries      IRremote by shirriff, z3t0 and
                                  ArminJo, version 4 or later
    Serial Monitor                115200
*/

#include <IRremote.hpp>

// The pin SIGNAL is wired to.
// Uno: 2. ESP32: 23. ESP32-S3: 9. Pico: 16.
const int IR_RX_PIN = 2;

// Every address-and-command pair seen so far.
const int MAX_KEYS = 32;
uint32_t seen[MAX_KEYS];
int keys = 0;

bool firstTime(uint32_t key) {
  for (int i = 0; i < keys; i++) {
    if (seen[i] == key) return false;
  }
  if (keys < MAX_KEYS) seen[keys++] = key;
  return true;
}

void setup() {
  Serial.begin(115200);
  // DISABLE_LED_FEEDBACK: leave your board's own LED alone.
  IrReceiver.begin(IR_RX_PIN, DISABLE_LED_FEEDBACK);
  Serial.println("Press every button on the remote.");
}

void loop() {
  if (!IrReceiver.decode()) return;     // no whole frame yet

  IRData &d = IrReceiver.decodedIRData;
  if (d.flags & IRDATA_FLAGS_IS_REPEAT) {
    Serial.println("[repeat]");         // a held button
  } else if (d.protocol == UNKNOWN) {
    Serial.println("UNKNOWN: no decoder matched this frame");
  } else {
    Serial.print(getProtocolString(d.protocol));
    Serial.print("  address=0x");
    Serial.print(d.address, HEX);
    Serial.print("  command=0x");
    Serial.print(d.command, HEX);
    uint32_t key = ((uint32_t)d.address << 16) | d.command;
    if (firstTime(key)) {
      Serial.print("  first time, ");
      Serial.print(keys);
      Serial.print(" so far");
    }
    Serial.println();
  }

  IrReceiver.resume();    // nothing else decodes until this runs
}

Holding a button prints [repeat], which is NEC working, not a fault. If every press prints UNKNOWN, the remote is not one of the protocols the library knows; codes belong to remotes explains what to do with it.

When it does not work

Nothing prints at all

Watch the TK15's red LED. If it flickers when you press a button, the board and the remote are fine and the fault is the SIGNAL wire or the pin number. If it does not, check GND and VCC, and that the remote has batteries: none come in the kit.

Every press prints UNKNOWN

A frame arrived that no decoder recognised. Air-conditioner remotes are the usual cause: they send a hundred bits or more. On an Uno the library's buffer holds 200 entries; define a larger, even RAW_BUFFER_LENGTH on the line before the #include, as far as the Uno's 2 KB of memory allows. An ESP32 or a Pico already holds 750.

One press prints several lines

You are holding the button. NEC sends the code once, then a short repeat frame every 110 ms while the key is down, and the sketch prints [repeat] for each. One press, one action means skipping repeats, as the sketch does.

It decodes the first press and then goes silent

IrReceiver.resume() is missing, or sits in a branch that did not run. The library holds the frame until you release it, so without that call it never looks at another, and nothing reports an error.

analogWrite stopped working on pin 3 or 11

On an Uno the library receives with Timer2, and Timer2 drives PWM on pins 3 and 11. Move that output to pin 5, 6, 9 or 10. It is receiving that costs those pins, not sending.

The Serial Monitor stays empty on my ESP32-S3

Set Tools > USB CDC On Boot to Enabled and upload again. Without it the S3's USB port brings up no serial port at boot, so the sketch runs with nowhere to print.

Where this goes next

What those two numbers are made of, and why half of every frame is a copy of the other half.

Thirty-two bits of NEC

Edit this page — content/books/ir-receiver/your-first-key-code.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

This page covers several products. Choose yours to see the right discussions.

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum