Additional Lab: Photoresistor
Pixel says...
Let's give your Pico a sense of sight! A photoresistor is like a tiny eye. The more light it
sees, the more electricity it lets through. We can measure that and turn it into LED colors.
Program files: 02-photoresistor-test.py,
03-photoresistor-bar.py, and
04-photoresistor-nightlight.py
in the extras kit folder
A photoresistor (a part that changes its resistance when light hits it) lets your Pico "see" how bright a room is. In this lab we read the light level, print it, show it as a bar on the LED strip, and then build a nightlight.
What you'll learn
- What a photoresistor is and how it changes with light
- How to read an analog value with the Pico's ADC
- How to turn a light reading into a bar of LED colors
- How a nightlight uses a threshold (a cut-off number) to decide when to turn on
What you'll need
- Your base kit: a Pico, a breadboard, and the 30-pixel LED strip, wired as shown in the Kit User's Guide
- Two extra parts: a photoresistor and a fixed resistor (10 kΩ is a common choice)
- Jumper wires
- The
config.pyfrom the extras kit folder, saved on the Pico (see below)
Not yet tested on hardware
The three programs for this lab are in src/kits/moving-rainbow-extras/. They follow the same pattern as the base-kit programs, but they have not been run on a real kit yet. Each one says so in its header. If something does not work, check the wiring and the numbers in config.py first.
Wiring the sensor
The photoresistor is one half of a voltage divider (two parts that split a voltage between them). Wire it like this:
| Part | Goes between | Pico pin |
|---|---|---|
| Photoresistor | 3V3(OUT) and the middle point |
Pin 36 |
| Fixed resistor | The middle point and ground | Any GND pin |
| Middle point (the wire to the Pico) | Where the two parts meet | GP28, pin 34 |
As the light changes, the voltage at the middle point changes too. More light means less resistance in the photoresistor, so the voltage at the middle point goes up. Try the Pico Light Sensor Circuit simulation to see it happen. The Photoresistor Component simulation shows the part itself.
The extras config.py
The base kit's config.py has no sensor pins, because the base kit has no sensors. The extras kit has its own config.py. It holds every base-kit setting plus the pins for the extra parts. Save it on your Pico in place of the base one.
# Moving Rainbow Extras Configuration file
# Filename: config.py
# Version: 1.0.0
#
# This file contains the hardware configuration for the base kit PLUS the
# extra sensor parts. It has every setting from the base kit's config.py,
# so save this file on your Pico in place of the base kit's config.py.
NEOPIXEL_PIN = 0
NUMBER_PIXELS = 30
BUTTON_PIN_1 = 15
BUTTON_PIN_2 = 14
# extra parts that are not in the base kit
POT_PIN = 26 # potentiometer middle leg (GP26, an ADC pin)
PHOTORESISTOR_PIN = 28 # photoresistor voltage divider (GP28, an ADC pin)
The line PHOTORESISTOR_PIN = 28 tells the programs that the sensor is wired to GP28.
Reading the light level
The Pico reads the middle-point voltage with its ADC (analog-to-digital converter, a part that turns a voltage into a number). The number runs from 0 to 65535.
Key idea
A bigger number means more light. In a dark room you might read about 1,500. In a bright room you might read about 55,000. Your room will be different, so test it first!
This first program reads the light level and prints it. Run it, then wave your hand over the sensor or cover it with your finger.
# Extras Lab 02: Photoresistor Test
# Filename: 02-photoresistor-test.py
# Version: 1.0.0
#
# Read the light level from a photoresistor and print it in the Shell.
# Needs a photoresistor (an extra part) and the extras config.py.
# Not yet tested on hardware: adapt for your setup.
from machine import ADC
from utime import sleep
import config
# hardware settings from config.py
PHOTORESISTOR_PIN = config.PHOTORESISTOR_PIN
photo = ADC(PHOTORESISTOR_PIN)
while True:
light_value = photo.read_u16() # a number from 0 to 65535
print(light_value) # show it in the Shell
sleep(0.2) # wait a fifth of a second
You should see numbers stream by in the Shell. Cover the sensor and the numbers drop. Shine a light on it and they jump up.
Tip
Write down your darkest number and your brightest number. You will use them in the next program.
Showing the light level on the strip
This program turns the light reading into a bar of colored pixels. The darker the room, the fewer pixels light up.
# Extras Lab 03: Photoresistor Bar
# Filename: 03-photoresistor-bar.py
# Version: 1.0.0
#
# Show the light level as a bar of colored pixels: the brighter the room,
# the longer the bar. Needs a photoresistor (an extra part) and the extras
# config.py.
# Not yet tested on hardware: adapt for your setup.
from machine import Pin, ADC
from neopixel import NeoPixel
from utime import sleep
import config
# hardware settings from config.py
NEOPIXEL_PIN = config.NEOPIXEL_PIN
NUMBER_PIXELS = config.NUMBER_PIXELS
PHOTORESISTOR_PIN = config.PHOTORESISTOR_PIN
strip = NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
photo = ADC(PHOTORESISTOR_PIN)
DARK_VALUE = 2000 # change to the number you wrote down for a dark room
BRIGHT_VALUE = 55000 # change to the number you wrote down for a bright room
BAR_PIXELS = 12 # the bar can be up to 12 pixels long
while True:
light_value = photo.read_u16()
# turn the light level into a bar length from 0 to BAR_PIXELS
if light_value <= DARK_VALUE:
lit = 0
elif light_value >= BRIGHT_VALUE:
lit = BAR_PIXELS
else:
lit = int((light_value - DARK_VALUE) / (BRIGHT_VALUE - DARK_VALUE) * BAR_PIXELS)
for i in range(NUMBER_PIXELS):
if i >= lit:
strip[i] = (0, 0, 0) # off
elif i < 4:
strip[i] = (0, 0, 25) # low light: blue
elif i < 8:
strip[i] = (0, 25, 0) # medium light: green
else:
strip[i] = (25, 0, 0) # high light: red
strip.write()
sleep(0.2)
You should see a bar that grows when the room is bright and shrinks when you cover the sensor.
Heads up
If the bar never changes, your sensor's numbers may be different from 2000 and 55000. Go back to the first program, find your real dark and bright numbers, and put them in DARK_VALUE and BRIGHT_VALUE.
The nightlight
A nightlight flips the idea around. It turns the pixels on when the room gets dark. We pick a threshold. When the light reading drops below the threshold, the strip turns on.
# Extras Lab 04: Photoresistor Nightlight
# Filename: 04-photoresistor-nightlight.py
# Version: 1.0.0
#
# A nightlight: the strip glows a dim, warm color when the room gets dark
# and turns off when the room is bright. Needs a photoresistor (an extra
# part) and the extras config.py.
# Not yet tested on hardware: adapt for your setup.
from machine import Pin, ADC
from neopixel import NeoPixel
from utime import sleep
import config
# hardware settings from config.py
NEOPIXEL_PIN = config.NEOPIXEL_PIN
NUMBER_PIXELS = config.NUMBER_PIXELS
PHOTORESISTOR_PIN = config.PHOTORESISTOR_PIN
strip = NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
photo = ADC(PHOTORESISTOR_PIN)
LIGHT_THRESHOLD = 10000 # below this number, the room is "dark"
GLOW = (20, 10, 0) # a dim, warm color
while True:
if photo.read_u16() < LIGHT_THRESHOLD:
color = GLOW # dark room: turn the nightlight on
else:
color = (0, 0, 0) # bright room: turn it off
for i in range(NUMBER_PIXELS):
strip[i] = color
strip.write()
sleep(0.5)
Cover the sensor and the strip glows warm. Uncover it and the strip turns off. Pick a LIGHT_THRESHOLD between your dark and bright numbers.
Two ways to build a nightlight
- An analog nightlight uses no code. A transistor and a photoresistor act as a switch, and the light turns on by itself when it gets dark. See the Analog Nightlight kit.
- A digital nightlight uses the Pico and the code above. Because it runs code, you can add patterns, colors, and brightness control. See the Digital Nightlight kit.
Try it yourself
- Change
LIGHT_THRESHOLDso the light comes on at dusk instead of full dark. - Make the bar use a rainbow of colors instead of blue, green, and red. The
wheel()function from Lab 09: Color Wheel can help.
Check your understanding
- What does a photoresistor do when more light hits it?
- What range of numbers does the Pico's ADC return?
- Why do we test the sensor before choosing a threshold?
- What is the difference between an analog and a digital nightlight?
Lab complete!
You taught your Pico to react to the world around it! Robots, weather stations, and smart lights all start with this same idea.
What's next: Head back to the Hands on Labs to try a game, or design a nightlight that is all your own.