Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.

IR receiver VS1838B with Raspberry Pi Pico W — decode remotes in MicroPython

Decode NEC TV and set-top-box remote buttons with a VS1838B IR receiver on a Pico W (GP16, 3.3 V) using time_pulse_us in MicroPython, no library.

MicroPythonVerified — micropython (mpy-cross v1.29.0), 3 Nov 2026Compile-only

Community draft — report a mistake

A VS1838B turns the 38 kHz flashes from a remote into a clean digital signal. The Pico W times those pulses on GP16 with machine.time_pulse_us() and decodes the NEC protocol used by most cheap remotes.

Power it from 3V3, run the script, and press buttons: each prints its address and command code.

Wiring

Raspberry Pi Pico WOnly the pins used are shown · 3.3 V logicVS1838B IR receiver (38 kHz)GND3V3GP16OUTGNDVCC
Every connection
Raspberry Pi Pico WVS1838B IR receiver (38 kHz)WireNotes
GP16OUTyellowGP16 is physical pin 21.
GNDGNDblack
3V3VCCred3V3 is pin 36. OUT then idles at 3.3 V.

2.7–5.5 V part, 3.3 V board. Power it from your board's logic voltage; OUT is an active-LOW signal at VCC level.

Board quirks

  • Most kit, LED-strip and many set-top-box remotes use the NEC protocol: a 9 ms burst, a 4.5 ms gap, then 32 bits. Holding a button sends short “repeat” codes, shown as “(held)”.
  • Each code carries its command and the inverted command; the script drops any code where they don’t match, so sunlight or CFL flicker can’t trigger it.
  • Write down the Command value for each button and use it in your own if statements — the start of an IR-remote fan or light controller.
  • On the bare VS1838B the pins are OUT, GND, VCC from the left with the dome facing you. Modules on a small PCB may order them differently — follow the print.

Code

main.pyMicroPython
# VS1838B IR receiver on a Raspberry Pi Pico W (MicroPython): decode NEC remote buttons.
# Wiring: OUT -> GP16 (pin 21), GND -> GND, VCC -> 3V3 (pin 36).
# Most cheap Indian set-top-box, LED-strip and kit remotes use the NEC protocol.
from machine import Pin, time_pulse_us
import time

ir = Pin(16, Pin.IN)
led = Pin("LED", Pin.OUT)


def read_nec():
    """Returns (address, command), "repeat", or None. OUT idles HIGH and goes LOW during IR bursts."""
    t = time_pulse_us(ir, 0, 100_000)    # wait for and time the 9 ms leader burst
    if t < 8000:
        return None
    t = time_pulse_us(ir, 1, 6000)       # then the space: 4.5 ms = new code, 2.25 ms = repeat
    if 1800 < t < 2700:
        return "repeat"
    if t < 3800:
        return None
    bits = 0
    for i in range(32):                  # each bit: 560 us burst, then 560 us (0) or 1690 us (1) space
        t = time_pulse_us(ir, 1, 3000)
        if t < 0:
            return None
        if t > 1000:
            bits |= 1 << i               # NEC sends LSB first
    addr, naddr, cmd, ncmd = bits & 0xFF, (bits >> 8) & 0xFF, (bits >> 16) & 0xFF, bits >> 24
    if cmd ^ ncmd != 0xFF:
        return None                      # corrupted (sunlight, CFL flicker, too far)
    if addr ^ naddr != 0xFF:
        addr = addr | (naddr << 8)       # "extended NEC" remotes use a 16-bit address
    return addr, cmd


print("IR receiver on GP16 - point a remote at it and press buttons")
while True:
    code = read_nec()
    if code == "repeat":
        print("  (held)")
    elif code:
        led.toggle()
        print("Address 0x{:02X}  Command 0x{:02X}".format(code[0], code[1]))

Expected serial output

REPL / Thonny shellOutput
IR receiver on GP16 - point a remote at it and press buttons
Address 0x00  Command 0x45
Address 0x00  Command 0x46
  (held)

Common errors

Nothing happens when buttons are pressed

The remote may not be NEC (many TV brands use RC5 or their own protocol). Try a kit remote first; check OUT is on GP16.

Only some presses are decoded

The script is busy printing when the next code starts. Press a little slower, or move printing out of the decode loop.

↑↓ to move · Enter to open