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 W | VS1838B IR receiver (38 kHz) | Wire | Notes |
|---|---|---|---|
| GP16 | OUT | yellow | GP16 is physical pin 21. |
| GND | GND | black | |
| 3V3 | VCC | red | 3V3 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
ifstatements — 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
# 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]))# 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
IR receiver on GP16 - point a remote at it and press buttons
Address 0x00 Command 0x45
Address 0x00 Command 0x46
(held)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.