One button, one job
Three buttons on the remote, one LED: one button switches it on and off, two dim it up and down. The sketch is short; the decision in it is what a held button means, because a held button arrives as a stream of repeat frames.
Three buttons, one LED
Wire the TK15 exactly as for your first key code, and an LED on a PWM pin: a TK01 XL LED, or any LED with its resistor. The LED pin is D9 on an Uno, GPIO 4 on an ESP32, GPIO 5 on an ESP32-S3 and GP15 on a Pico.
Then pick three buttons on the remote, run the key-code sketch, and put their
command values into CMD_POWER, CMD_UP and CMD_DOWN. The sketch's values
are placeholders.
What a held button sends
A tap is one data frame. A hold is one data frame and then a repeat frame
every 110 ms for as long as the button is down. The repeat carries no data;
IRremote fills in the command of the frame it repeats and sets
IRDATA_FLAGS_IS_REPEAT.
So the sketch has to decide, per button, what a repeat means. For power it means nothing: the toggle skips repeats and changes once per press. For brightness it means "keep going": each repeat is another step.
What you should see
off 128
on 128
on 144
on 160
on 176
off 176Power, then holding the up button for about a quarter of a second (a data frame and two repeats), then power again. The level is kept while the LED is off.
Why not match the address
The sketch compares commands only. With one remote pointed at the board that
is enough, and it keeps working if a second remote of the same kind turns up
with a different address. If two remotes in the room share command values,
check d.address as well.
The code
One button toggles an LED, two more dim it. Put three commands your own remote sent to the key-code sketch into CMD_POWER, CMD_UP and CMD_DOWN; the values here are placeholders. The address is not checked: one remote is pointed at this.
/*
IR Receiver - one button, one job 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
The LED: a TK01 XL LED (SIGNAL to LED_PIN, GND to GND), or any LED
with a resistor, on D9, GPIO 4, GPIO 5 or GP15.
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;
// A PWM pin for the LED. Uno: 9. ESP32: 4. ESP32-S3: 5. Pico: 15.
const int LED_PIN = 9;
// REPLACE THESE with commands your own remote sent.
const uint16_t CMD_POWER = 0x16; // toggles: repeats ignored
const uint16_t CMD_UP = 0x17; // dims up: every repeat counts
const uint16_t CMD_DOWN = 0x18; // dims down: every repeat counts
bool on = false;
int level = 128; // 16 to 255
void show() {
analogWrite(LED_PIN, on ? level : 0);
Serial.print(on ? "on " : "off ");
Serial.println(level);
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
IrReceiver.begin(IR_RX_PIN, DISABLE_LED_FEEDBACK);
show();
}
void loop() {
if (!IrReceiver.decode()) return;
IRData &d = IrReceiver.decodedIRData;
// A repeat frame carries no data; the library fills in the
// command of the frame it repeats.
bool repeat = d.flags & IRDATA_FLAGS_IS_REPEAT;
if (d.command == CMD_POWER && !repeat) {
on = !on; // once per press
show();
} else if (d.command == CMD_UP && on) {
level = min(level + 16, 255); // held: keeps going
show();
} else if (d.command == CMD_DOWN && on) {
level = max(level - 16, 16);
show();
}
IrReceiver.resume(); // nothing else decodes until this runs
}The power button ignores repeat frames, so holding it toggles once. The dimming buttons act on every repeat, so holding one keeps going, a step every 110 ms. On an Uno the LED pin must not be 3 or 11: receiving takes Timer2, which drives their PWM.
The same three buttons in MicroPython, for an ESP32, an ESP32-S3 or a Pico. micropython_ir reports a repeat frame as a negative number with no command in it, so the sketch remembers the last real command itself.
"""
IR Receiver - one button, one job, MicroPython TK15 / /p/tk15
Wiring. Count from the square pad on the TinkerBlock board, parts
up, header at the bottom:
GND -> GND
VCC -> 3V3 (SIGNAL idles at VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 23 on an ESP32, GPIO 9 on an ESP32-S3,
GP16 on a Raspberry Pi Pico
The LED: a TK01 XL LED (SIGNAL to LED_PIN, GND to GND), or any LED
with a resistor, on GPIO 4, GPIO 5 or GP15.
Install once, from a computer:
mpremote mip install "github:peterhinch/micropython_ir/ir_rx"
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
"""
import time
from machine import Pin, PWM
from ir_rx.nec import NEC_8
# The GPIO number SIGNAL is wired to. ESP32: 23. ESP32-S3: 9. Pico: 16.
IR_RX_PIN = 9
# A PWM pin for the LED. ESP32: 4. ESP32-S3: 5. Pico: 15.
LED_PIN = 5
# REPLACE THESE with commands your own remote sent.
CMD_POWER = 0x16 # toggles: repeats ignored
CMD_UP = 0x17 # dims up: every repeat counts
CMD_DOWN = 0x18 # dims down: every repeat counts
led = PWM(Pin(LED_PIN), freq=1000)
on = False
level = 128 # 16 to 255
last = None # the command a repeat repeats
def show():
led.duty_u16(level * 257 if on else 0)
print("on " if on else "off", level)
def got(command, address, ctrl):
global on, level, last
repeat = command < 0 # a repeat frame carries no data
if repeat:
command = last
else:
last = command
if command == CMD_POWER and not repeat:
on = not on # once per press
elif command == CMD_UP and on:
level = min(level + 16, 255)
elif command == CMD_DOWN and on:
level = max(level - 16, 16)
else:
return
show()
ir = NEC_8(Pin(IR_RX_PIN, Pin.IN), got)
show()
while True:
time.sleep_ms(500)Replace the three commands with your remote's. duty_u16 takes 0 to 65535, so the 0 to 255 level is multiplied by 257. Install ir_rx once with mpremote, as the comment says. Stop it with Ctrl-C.
When it does not work
The toggle is acting on repeat frames. Holding the button sends one data frame and a repeat every 110 ms, and a toggle that counts them lands on or off at random. Skip anything flagged IRDATA_FLAGS_IS_REPEAT for a toggle.
The three commands in the sketch are still the placeholders. Replace them with the command values your own remote printed; the address does not matter here.
The LED is on pin 3 or 11. Receiving takes Timer2, which drives PWM on those two pins. Use pin 9, 10, 5 or 6.
The sketch stops at 16 so off stays the power button's job. Change the 16 in the dim-down line to 0 if you want dimming to reach dark.
One LED, one transistor, and where its current comes from.
The sender, pin by pin →Edit this page — content/books/ir-receiver/one-button-one-job.mdx
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.