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.

LDR light sensor with Raspberry Pi Pico W — MicroPython analog and digital

Read an LDR light-sensor module on a Pico W: AO on ADC1 (GP27), DO on GP16, powered from 3V3 so neither output can exceed the Pico’s limit.

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

Community draft — report a mistake

LDR modules give you two signals: AO, an analog voltage you can measure, and DO, an on/off output from a comparator whose threshold you set with a screwdriver. The Pico W reads AO on GP27 (ADC1) and DO on any GPIO.

Power it from 3V3 and both outputs are safe for the Pico. The script prints the light level once a second and turns the on-board LED on when it gets dark.

Wiring

Raspberry Pi Pico WOnly the pins used are shown · 3.3 V logicLDR light sensor moduleGND3V3GP27GP16VCCGNDDOAO
Every connection
Raspberry Pi Pico WLDR light sensor moduleWireNotes
3V3VCCred3V3 is pin 36. Powered from 3.3 V, AO and DO stay inside the Pico’s range.
GNDGNDblack
GP27AOgreenGP27 = ADC1, physical pin 32.
GP16DOyellowGP16 is physical pin 21.

3.3–5 V part, 3.3 V board. AO swings up to VCC. On ESP32 and Pico, power the module from 3.3 V so AO never exceeds the ADC's 3.3 V limit; on Uno use 5 V.

Board quirks

  • On most modules AO falls as light increases; the script inverts it so 100 % means bright. Check yours with a phone torch.
  • DO is the LM393 comparator: turn the blue pot until its LED flips at the light level you want — that is your “dusk” threshold with no code changes.
  • Do not power the module from VBUS: AO would swing to 5 V, and GP26–GP28 are not 5 V tolerant.
  • The on-board LED (Pin("LED")) lights when DO says “dark”, like a street light.

Code

main.pyMicroPython
# LDR light-sensor module on a Raspberry Pi Pico W (MicroPython).
# Wiring: VCC -> 3V3 (pin 36), GND -> GND, AO -> GP27 / ADC1 (pin 32), DO -> GP16 (pin 21).
# Powered from 3V3 the module's outputs never exceed 3.3 V, so no divider is needed.
from machine import ADC, Pin
import time

ao = ADC(27)                 # analog: lower voltage = more light on most modules
do = Pin(16, Pin.IN)         # comparator output, threshold set with the blue pot
led = Pin("LED", Pin.OUT)


def light_percent():
    raw = sum(ao.read_u16() for _ in range(8)) // 8
    return 100 - raw * 100 // 65535, raw  # invert so 100 % = bright


while True:
    pct, raw = light_percent()
    dark = do.value() == 1   # DO goes HIGH when it is darker than the pot setting
    led.value(dark)          # on-board LED = "it's dark", like a street light
    print("Light {:3d} %  (raw {:5d})  DO={}  {}".format(pct, raw, do.value(), "dark" if dark else "bright"))
    time.sleep(1)

Expected serial output

REPL / Thonny shellOutput
Light  82 %  (raw 11796)  DO=0  bright
Light  81 %  (raw 12452)  DO=0  bright
Light  12 %  (raw 57671)  DO=1  dark

Common errors

DO never changes

The threshold pot is at one end. Turn it slowly until the module’s DO LED toggles while you cover the LDR.

Percent is backwards

Some modules put the LDR on the other side of the divider. Remove the 100 - in light_percent().

↑↓ to move · Enter to open