- Explain why the Pi needs an ADC for analog voltage.
- Wire an MCP3008 to SPI0 at 3.3 V.
- Build a light-dependent voltage divider.
- Interpret normalized readings without calling them lux.
- Distinguish a sensor fault from a software fault.
Before you begin
Complete PI06 and understand breadboard rows and series connections. Use the 16-pin through-hole MCP3008, not a differently pinned breakout.
The missing link between voltage and Python
A button produces two useful states. Light, temperature and rotation change more continuously. Many sensors express those changes as a varying voltage, but the Pi’s standard GPIO header does not provide general-purpose analog voltage inputs. An analog-to-digital converter, or ADC, translates voltage into a number.
Our MCP3008 has multiple input channels and ten-bit resolution. Ten bits represent 1,024 distinct codes; they do not promise laboratory accuracy. Noise, reference stability, wiring and the sensor’s own behavior affect the measurement. GPIO Zero exposes a convenient normalized value between zero and one.
The ADC communicates with the Pi through SPI, a clocked serial interface. One wire carries outgoing data, one incoming data, another the clock and another selects the device. This is different from connecting an analog voltage directly to a digital GPIO.
Build the 3.3 V circuit
Use a Pi 4 or 5, MCP3008 in a 16-pin DIP package, breadboard, jumper wires, an LDR light-dependent resistor and a 10 kΩ fixed resistor. A 10 kΩ potentiometer is an optional substitute for the divider during testing. Keep every part of this exercise on 3.3 V and ground; do not use the Pi’s 5 V pins.
Disconnect power before wiring. With the notch facing up, DIP pin numbers run counterclockwise from the upper-left pin. Check the manufacturer’s package drawing rather than relying on this sentence alone. Power VDD and VREF from 3.3 V. Join analog and digital ground to Pi ground. The table lists chip pins, BCM signals and physical header positions separately.
Make a divider: 3.3 V to LDR, LDR to a junction, junction to 10 kΩ resistor, resistor to ground. Connect the junction to MCP3008 CH0. In this arrangement, stronger light usually lowers the LDR resistance and raises the junction voltage. Swapping the positions reverses the response. The junction is never connected to a GPIO input directly.
| MCP3008 DIP pin | Pi connection |
|---|---|
| 16 VDD and 15 VREF | 3.3 V, physical pin 1 |
| 14 AGND and 9 DGND | Ground, physical pin 6 |
| 13 CLK | GPIO11 SCLK, physical pin 23 |
| 12 DOUT | GPIO9 MISO, physical pin 21 |
| 11 DIN | GPIO10 MOSI, physical pin 19 |
| 10 CS/SHDN | GPIO8 CE0, physical pin 24 |
| 1 CH0 | LDR/resistor junction |
3.3 V → LDR → junction → 10 kΩ → ground
↓
CH0 ADC → SPI → Pi → PythonEnable the interface and read it
Use Raspberry Pi OS configuration to enable SPI; the terminal tool sudo raspi-config exposes interface settings. Reboot if requested. Keep the GPIO Zero installation from PI06. Use python3 from that same OS environment; a separate virtual environment does not automatically inherit system packages.
Save the following as read_light.py and run python3 read_light.py. It prints a finite set of observations, then releases the ADC. A median takes the middle reading from a small batch; this reduces the influence of an isolated spike, but does not fix reversed wiring or an inappropriate sensor.
The voltage estimate multiplies the normalized reading by the nominal 3.3 V reference. If the actual reference differs, so does the estimate. The printed decimals are formatting, not a claim of four-decimal measurement precision.
from gpiozero import MCP3008
from statistics import median
from time import sleep
with MCP3008(channel=0) as light:
print("sample,ratio,estimated_volts")
for sample in range(30):
readings = []
for _ in range(5):
readings.append(light.value)
sleep(0.01)
ratio = median(readings)
print(f"{sample},{ratio:.4f},{ratio * 3.3:.3f}")
sleep(0.5)MCP3008 selects channel zero with default SPI0 chip select zero, matching CE0. median combines five readings. The context manager closes the interface after thirty printed observations.
Expected result: A CSV-style header and thirty rows. Covering the LDR should usually lower the ratio with this divider orientation; exact numbers depend on the room and components.
Calibration is a controlled comparison
Record readings under three repeatable conditions: uncovered room light, a partial shade and full cover. Keep the position and supply unchanged. Take several observations per condition and describe the spread, not only a favorite single reading.
Do not label the output lux. Lux is a physical illumination unit, while this circuit produces a divider ratio influenced by a nonlinear, component-dependent resistance. Without a suitable calibration against a trusted reference, “brighter than before” is a more defensible claim than an absolute illumination number.
A digital temperature module might already contain an ADC and calibration logic and communicate over I²C or another interface. A motion module may instead give a simple high/low event. Read the module’s output type, supply voltage and signal voltage before choosing a library. A three-wire cable alone does not identify a protocol.
For later machine learning, save the conditions alongside readings. A file of measurements without labels, timestamps or collection context is harder to interpret. Keep separate collection sessions if you intend to test generalization; neighboring readings are often too similar to act as independent evidence.
Diagnose flat lines and unstable readings
If the output remains near zero or one in all conditions, stop before calling it a model problem. Check reference power, shared ground, chip orientation and whether CH0 reaches the divider junction. A reading at an endpoint can be legitimate, so compare it with a controlled input before assuming failure.
An optional potentiometer test replaces the LDR divider: connect its two outer terminals to 3.3 V and ground, and its wiper to CH0. Slowly rotating it should span much of the range. Verify the terminal roles first. Disconnect power to change the circuit and never bridge power rails with the wiper lead.
If software cannot open SPI, confirm that it is enabled and that no incompatible configuration occupies the pins. If the readings are noisy, shorten loose leads, check the breadboard contacts and keep the setup away from motor wiring. Averaging can hide a symptom; a reliable circuit fixes its cause.
This project is a measuring instrument only in the modest sense of observing a local signal. It is not suitable for medical measurement, mains monitoring or a safety-critical alarm. The useful milestone is a repeatable change tied to a known input, with limitations recorded.
Important terms
- ADC
- A device that converts analog voltage into a digital code.
- Reference voltage
- The voltage that sets the converter’s measurement scale.
- SPI
- A clocked serial interface with separate data and selection signals.
- Voltage divider
- Two series resistances that produce an intermediate junction voltage.
- Calibration
- Comparing readings with known conditions or a trusted reference.
Mini project: A three-condition light log
- Inspect the unpowered pin map and divider.
- Enable SPI and run thirty observations.
- Repeat for uncovered, partly covered and covered conditions.
- Record ranges and decide whether the three conditions are distinguishable. Keep a note that these are ratios, not lux.
Common mistakes and debugging
- Powering the ADC at 5 V can expose Pi signals to unsafe levels: use the stated 3.3 V circuit.
- Calling the ratio lux invents a calibration: report the actual quantity.
- Connecting CH0 to an arbitrary breadboard row: trace the shared divider junction.
- Mixing ADC chip pins with Pi header positions: keep the table visible while wiring.
Independent challenge
Replace the LDR with the optional potentiometer. Predict the trend first, then compare predicted and measured direction without changing the Python program.
Check your understanding: 10 questions
Why add an ADC to the Pi?
How many codes can ten bits represent?
Why connect VREF?
Which chip channel does the example read?
Which Pi chip-select signal is used?
Why share ground?
What usually happens when this LDR is shaded?
Does more printed precision improve accuracy?
Can median filtering repair a wrong pin connection?
What would a potentiometer test isolate?
Quiz answers
Reveal all 10 answers after your attempt
- Its standard GPIO does not directly measure a continuously varying analog voltage.
- 1,024 distinct codes, usually numbered zero through 1,023.
- It establishes the ADC conversion scale.
- CH0, chip pin 1 on the specified DIP package.
- SPI0 CE0 on GPIO8, physical pin 24.
- Signals and voltage measurements need a common electrical reference.
- Its resistance rises, lowering the divider junction voltage in the stated orientation.
- No; formatting extra decimals does not improve the circuit or reference.
- No. It can reduce isolated numerical spikes, not change the circuit.
- Whether the ADC and software follow a controlled voltage, separately from LDR behavior.
Summary
A sensor reading is the end of an electrical and software chain. You can now build that chain, record repeatable changes and avoid claiming units your circuit has not measured.
Continue learning
PI08 replaces a single measurement with a camera image containing many pixels and introduces reproducible image processing.
- Raspberry Pi Cameras and Computer Vision
- Training Data: Quality, Bias, Cleaning, and Data Splits
- Arduino Communication: Serial, I²C, SPI, Bluetooth, and Wi-Fi
Sources and further reading
Prepared 2026-09-19. Editorial draft. Primary documentation checked 19 September 2026. Code requires the stated Pi environment; no physical wiring, camera or performance test is claimed.