When nothing decodes
There is no error message anywhere in an infrared link, and half of it is invisible. This sketch makes one board send to itself, so a failure becomes a printed line and two red LEDs rather than a silence you have to guess at.
Why a loop-back
Every other test of an infrared link has two unknowns: did the sender send, and did the receiver hear? Neither board can say, because what is between them is invisible and the protocol has no acknowledgement. With both blocks on one board the sketch knows what it sent and checks what came back. A failure becomes a printed line.
Which end is the problem
Serial output cannot tell you where a fault is. The two red LEDs can.
The TK16's red LED is on the same transistor as the infrared LED, so it flickers every time a frame actually leaves.
The TK15's red LED runs into SIGNAL, so it flickers every time the receiver hears a carrier, before any code runs.
Between them they split the problem in a second. Sender's LED dark: look at the sender. Sender's flickering and receiver's dark: look at the air, the aim and the distance. Both flickering and nothing printed: look at the sketch.
Run it
Wire both blocks to one board, stand them face to face about 30 cm apart, parts side to parts side, and upload. A healthy link prints:
ok 1 of 1
ok 2 of 2
ok 3 of 3heard something, decoded nothing almost always means too close. See
how far, and how wide.
Five things that are not faults
The sender's LED looks dead. It is 940 nm; use a phone camera.
One press prints several lines. A held key sends a repeat frame every
110 ms. Check IRDATA_FLAGS_IS_REPEAT.
digitalRead on the receiver's SIGNAL always returns 1. That is the idle
level; each low lasts 560 µs, and the library samples on a timer for that
reason.
The codes differ from every example you have read. They belong to the remote that sent them.
UNKNOWN from an air-conditioner remote. It sends a hundred bits or more;
on an Uno, raise RAW_BUFFER_LENGTH before the include, or replay the raw
timings.
The code
One board, both blocks, sending to itself once a second. Point the TK16's lens at the TK15's window about 30 cm apart. It prints a line per frame and whether what came back is what went out.
/*
IR loop-back test TK15 + TK16 / /p/tbir
Wiring. Count from the square pad on each TinkerBlock board, parts
up, header at the bottom:
TK15 receiver
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
NC -> nothing (unconnected on the board)
SIGNAL -> D2, GPIO 23, GPIO 9 or GP16
TK16 sender
GND -> GND
VCC -> 5V, or VBUS on a Pico (only feeds the LEDs)
NC -> nothing (unconnected on the board)
SIGNAL -> D3, GPIO 22, GPIO 6 or GP17
Uno, ESP32, ESP32-S3, Pico, in that order.
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>
// Uno: 2. ESP32: 23. ESP32-S3: 9. Pico: 16.
const int IR_RX_PIN = 2;
// Uno: 3. ESP32: 22. ESP32-S3: 6. Pico: 17.
const int IR_TX_PIN = 3;
// Any pair nothing else in the room is likely to send.
const uint16_t ADDRESS = 0x12;
const uint8_t COMMAND = 0x34;
unsigned long sent = 0, back = 0;
void setup() {
Serial.begin(115200);
IrSender.begin(IR_TX_PIN);
IrReceiver.begin(IR_RX_PIN, DISABLE_LED_FEEDBACK);
Serial.println("Loop-back: sending once a second.");
}
void loop() {
Serial.flush(); // no interrupt mid-frame on an Uno
IrSender.sendNEC(ADDRESS, COMMAND, 0);
sent++;
// The library's own SendAndReceive order: restart the receiver,
// then wait long enough for it to see that the frame has ended.
IrReceiver.restartAfterSend();
delay(RECORD_GAP_MICROS / 1000 + 5);
if (IrReceiver.decode()) {
IRData &d = IrReceiver.decodedIRData;
if (d.protocol == UNKNOWN) {
Serial.println("heard something, decoded nothing: move apart");
} else if (d.address == ADDRESS && d.command == COMMAND) {
back++;
Serial.print("ok ");
} else {
Serial.print("someone else's frame ");
}
IrReceiver.resume();
} else {
Serial.print("nothing came back ");
}
Serial.print(back);
Serial.print(" of ");
Serial.println(sent);
delay(1000);
}Facing the two boards at each other from a few centimetres is the one arrangement that fails while everything works: the receiver is swamped and the decode breaks. Give them 30 cm, or bounce the light off a pale wall.
The same loop-back in MicroPython, with micropython_ir's receiver and sender on one board. The receiver's callback counts what came back; the loop sends and prints the tally once a second.
"""
IR loop-back test, MicroPython TK15 + TK16 / /p/tbir
Wiring. Count from the square pad on each TinkerBlock board, parts
up, header at the bottom:
TK15 receiver
GND -> GND
VCC -> 3V3 (SIGNAL idles at VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 23, GPIO 9 or GP16
TK16 sender
GND -> GND
VCC -> 5V, or VBUS on a Pico (only feeds the LEDs)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 22, GPIO 6 or GP17
ESP32, ESP32-S3, Pico, in that order.
Install once, from a computer:
mpremote mip install "github:peterhinch/micropython_ir/ir_rx"
mpremote mip install "github:peterhinch/micropython_ir/ir_tx"
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
"""
import time
from machine import Pin
from ir_rx.nec import NEC_8
from ir_tx.nec import NEC
# The GPIO numbers. ESP32: 23. ESP32-S3: 9. Pico: 16.
IR_RX_PIN = 9
# ESP32: 22. ESP32-S3: 6. Pico: 17.
IR_TX_PIN = 6
ADDRESS = 0x12 # any pair nothing else is sending
COMMAND = 0x34
sent = 0
back = 0
def got(command, address, ctrl):
global back
if command == COMMAND and address == ADDRESS:
back += 1
ir = NEC_8(Pin(IR_RX_PIN, Pin.IN), got)
nec = NEC(Pin(IR_TX_PIN, Pin.OUT, value=0))
print("Loop-back: sending once a second.")
while True:
nec.transmit(ADDRESS, COMMAND)
sent += 1
time.sleep(1)
print("ok" if back == sent else "missing", back, "of", sent)Sending is documented for the ESP32 and the Pico; on the ESP32-S3 it should work on the same port but is untested here. Install both packages once with mpremote, as the comment says. Stop it with Ctrl-C.
When it does not work
The sketch is not running, or not printing: check the port and the baud rate, and on an ESP32-S3 set USB CDC On Boot to Enabled. Every pass prints a line, whether or not anything came back.
The usual first result, and it usually means the boards are too close. Within about 20 cm the receiver is swamped and every mark it measures comes out long. Move them 30 cm apart or bounce the light off a pale wall.
Losing the odd frame at range or off to one side is normal for infrared, and it is why remotes repeat. Losing most of them by a window is daylight; losing most of them at any distance is aim.
A real remote in the room, or something that emits infrared: some motion sensors and camera autofocus lamps do. Not a fault, and a reminder that anything you build can be triggered by a neighbour's television.
Check what changes without anyone touching the wiring: the remote's batteries, the light through the window, and anything on the same supply that has started switching hard. The receiver has only 100 nF on its supply.
The sender's specifications, wiring and files in one place.
The TK16 reference page →Edit this page — content/books/ir-receiver/when-nothing-decodes.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.