Using a Pi Zero W with a sensor to read battery voltage.
Sensor, board, and pi
Voltage sensor: https://amzn.to/3AuDScb
The famous serial to digital converter: MCP3008 that’s actually easy to set up:
The board:
Voltage sensor:
Pi Zero W:
Lab power supply for testing:
Exact wiring instructions:
Wiring source: https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/mcp3008
A great tutorial, except he screws up and wires up Pi pin 22, which is incorrect — you need to wire Pi pin 24 instead. It’s a great tutorial though, check it out, both for Raspberry Pi and Arduino:
My setup that worked (August 2024)
# sudo raspi-config and enable SPI and reboot.
#
# Install libraries:
sudo apt-get install python3-pip
# create a sensors directory to work in
cd ~
mkdir sensors && cd sensors
# create a virtual environment
python3 -m vent .venv
# always run this after every reboot
source .venv/bin/activate
# install the drivers
pip3 install adafruit-circuitpython-mcp3xxx
pip install adafruit-mcp3008
The program that works: simpletest from https://github.com/adafruit/Adafruit_Python_MCP3008/blob/master/examples/simpletest.py
Here’s a copy, customized using hardware SPI, which you first enable and then reboot:
# Simple example of reading the MCP3008 analog input channels and printing
# them all out.
# Author: Tony DiCola
# License: Public Domain
import time
# Import SPI library (for hardware SPI) and MCP3008 library.
import Adafruit_GPIO.SPI as SPI
import Adafruit_MCP3008
# Hardware SPI configuration:
SPI_PORT = 0
SPI_DEVICE = 0
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
print('Reading MCP3008 values, press Ctrl-C to quit...')
# Print nice channel column headers.
print('| {0:>4} | {1:>4} | {2:>4} | {3:>4} | {4:>4} | {5:>4} | {6:>4} | {7:>4} |'.format(*range(8)))
print('-' * 57)
# Main program loop.
while True:
# Read all the ADC channel values in a list.
values = [0]*8
for i in range(8):
# The read_adc function will get the value of the specified channel (0-7).
values[i] = mcp.read_adc(i)
# Print the ADC values.
print('| {0:>4} | {1:>4} | {2:>4} | {3:>4} | {4:>4} | {5:>4} | {6:>4} | {7:>4} |'.format(*values))
# Pause for half a second.
time.sleep(1)
How it looks when it’s running:
I’m using only channel 0 out of 7 (there are 8 in total), so column 0 is showing the analog to digital value.
Reminder: it’s the top left pin for channel 0, my brown wire here:
Making sense of the numbers, I built a table of voltage supplied to the sensor, and the value the MCP3008 chip is reading, using the Adafruit library:
Notice that even though this sensor is rated to 24V max, I started getting a max sensor reading of 1023 when I reached about 17 volts, see table above.
It looks like the difference between 1 volt is about 62 sensor units, so the formula becomes:
Voltage = sensor_reading / 62
I tested some voltages and the live test matched the formula V = sensor / 62.
Pretty spot on voltage reading.
Next: TODO: make it all start up at boot on the pi zero w, set up a web interface to manage the readings, dump all readings to a system that graphs it all out.