.. note::
Hello, welcome to the SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Community on Facebook! Dive deeper into Raspberry Pi, Arduino, and ESP32 with fellow enthusiasts.
**Why Join?**
- **Expert Support**: Solve post-sale issues and technical challenges with help from our community and team.
- **Learn & Share**: Exchange tips and tutorials to enhance your skills.
- **Exclusive Previews**: Get early access to new product announcements and sneak peeks.
- **Special Discounts**: Enjoy exclusive discounts on our newest products.
- **Festive Promotions and Giveaways**: Take part in giveaways and holiday promotions.
👉 Ready to explore and create with us? Click [|link_sf_facebook|] and join today!
.. _3.1.5_py_pi5_mcp3008:
3.1.5 Battery Indicator(MCP3008)
===================================
.. note::
.. image:: ../img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
Depending on your kit version, please identify whether you have **ADC0834** or **MCP3008** and proceed with the matching section.
Introduction
--------------
In this project, we will make a battery indicator device that can
visually display the battery level on the LED Bargraph.
.. warning::
Do not use battery components that exceed 3.3V to avoid overloading, which may damage the chip or Raspberry Pi.
Required Components
------------------------------
In this project, we need the following components.
.. image:: ../python_pi5/img/list2_Battery_Indicator.png
:align: center
Schematic Diagram
-------------------
============ ======== ======== ===
T-Board Name physical wiringPi BCM
SPICE0 Pin 24 10 8
SPIMOSI Pin 19 12 10
SPIMISO Pin 21 13 9
SPISCLK Pin 23 14 11
GPIO25 Pin 22 6 25
GPIO12 Pin 32 26 12
GPIO16 Pin 36 27 16
GPIO20 Pin 38 28 20
GPIO21 Pin 40 29 21
GPIO5 Pin 29 21 5
GPIO6 Pin 31 22 6
GPIO13 Pin 33 23 13
GPIO19 Pin 35 24 19
GPIO26 Pin 37 25 26
============ ======== ======== ===
.. image:: ../python_pi5/img/schematic_battery_indicator_mcp3008.png
:align: center
:width: 800
Experimental Procedures
-------------------------
**Step 1:** Build the circuit.
.. image:: ../python_pi5/img/july24_3.1.5_battery_indicator_mcp3008.png
:width: 800
**Step 2:** Set up the SPI interface and install the ``spidev`` library (see :ref:`spi_configuration` for detailed instructions). If you have already completed these steps, you can skip this.
**Step 3:** Go to the folder of the code.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python-pi5
**Step 4:** Run the executable file.
.. raw:: html
.. code-block::
sudo python3 3.1.5-2_Battery_indicator_zero.py
After the program runs, give the 3rd pin of MCP3008 and the GND a
lead-out wire separately and then lead them to the two poles of a
battery separately. You can see the corresponding LED on the LED
Bargraph is lit up to display the power level (measuring range: 0-5V).
.. warning::
If there is an error prompt ``RuntimeError: Cannot determine SOC peripheral base address``, please refer to :ref:`faq_soc`
**Code**
.. note::
You can **Modify/Reset/Copy/Run/Stop** the code below. But before that, you need to go to source code path like ``davinci-kit-for-raspberry-pi/python-pi5``. After modifying the code, you can run it directly to see the effect.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import LCD1602
from gpiozero import LED, Buzzer, Button
import spidev
import time
import math
# Initialize joystick button, buzzer, and LED
Joy_BtnPin = Button(22) # GPIO22, Pin15
buzzPin = Buzzer(23) # GPIO23, Pin16
ledPin = LED(24) # GPIO24, Pin18
# Set initial upper temperature threshold
upperTem = 40
# Initialize SPI for MCP3008 (Bus 0, CE0 -> GPIO8 / Pin24)
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000 # 1 MHz
# Initialize LCD (I2C address 0x27, backlight on)
LCD1602.init(0x27, 1)
def read_adc(channel):
"""
Read analog value from MCP3008
"""
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
def get_joystick_value():
"""
Reads the joystick values and returns a change value based on the joystick's position.
"""
x_val = read_adc(1)
y_val = read_adc(2)
if x_val > 800:
return 1
elif x_val < 200:
return -1
elif y_val > 800:
return -10
elif y_val < 200:
return 10
else:
return 0
def upper_tem_setting():
"""
Adjusts and displays the upper temperature threshold on the LCD.
"""
global upperTem
LCD1602.write(0, 0, 'Upper Adjust: ')
change = int(get_joystick_value())
upperTem += change
strUpperTem = str(upperTem)
LCD1602.write(0, 1, strUpperTem)
LCD1602.write(len(strUpperTem), 1, ' ')
time.sleep(0.1)
def temperature():
"""
Reads the current temperature from the sensor and returns it in Celsius.
"""
analogVal = read_adc(0)
Vr = 3.3 * analogVal / 1023.0 # Voltage across the fixed resistor
if Vr == 0:
return 0 # Prevent division by zero
Rt = 10000.0 * (3.3 - Vr) / Vr # Adjusted formula: thermistor voltage is (3.3 - Vr)
temp = 1 / (((math.log(Rt / 10000.0)) / 3950.0) + (1 / (273.15 + 25.0)))
Cel = temp - 273.15
return round(Cel, 2)
def monitoring_temp():
"""
Monitors and displays the current temperature and upper temperature threshold.
Activates buzzer and LED if the temperature exceeds the upper limit.
"""
global upperTem
Cel = temperature()
LCD1602.write(0, 0, 'Temp: ')
LCD1602.write(0, 1, 'Upper: ')
LCD1602.write(6, 0, str(Cel))
LCD1602.write(7, 1, str(upperTem))
time.sleep(0.1)
if Cel >= upperTem:
buzzPin.on()
ledPin.on()
else:
buzzPin.off()
ledPin.off()
# Main execution loop
try:
lastState = 1
stage = 0
while True:
currentState = Joy_BtnPin.value
if currentState == 1 and lastState == 0:
stage = (stage + 1) % 2
time.sleep(0.1)
LCD1602.clear()
lastState = currentState
if stage == 1:
upper_tem_setting()
else:
monitoring_temp()
except KeyboardInterrupt:
LCD1602.clear()
spi.close()
**Code Explanation**
This Python program runs on a Raspberry Pi. It uses an MCP3008 analog-to-digital converter to read temperature data from an analog sensor. A joystick is used to adjust the temperature threshold, and an LCD1602 display shows the current temperature and threshold. A buzzer and LED are triggered when the temperature exceeds the threshold.
1. **Import Required Libraries**
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
import LCD1602
* ``RPi.GPIO`` is used for controlling GPIO pins.
* ``spidev`` communicates with MCP3008 using SPI.
* ``math`` is needed for temperature conversion calculations.
* ``LCD1602`` controls the LCD display.
2. **GPIO Setup**
.. code-block:: python
JOY_BTN_PIN = 22
BUZZER_PIN = 23
LED_PIN = 24
GPIO.setmode(GPIO.BCM)
GPIO.setup(JOY_BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(BUZZER_PIN, GPIO.OUT)
GPIO.setup(LED_PIN, GPIO.OUT)
* Assigns pins for joystick button, buzzer, and LED using BCM numbering.
* Configures the joystick button with a pull-up resistor and sets output pins LOW initially.
3. **SPI and LCD Initialization**
.. code-block:: python
upperTem = 40 # Default temperature threshold
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000 # 1 MHz
LCD1602.init(0x27, 1)
* Initializes SPI communication for the MCP3008.
* Sets up the I2C LCD1602 at address ``0x27``.
4. **Read ADC Channel**
.. code-block:: python
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
adc = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((adc[1] & 0x03) << 8) | adc[2]
return value
* Sends SPI commands to MCP3008 to read analog voltage from the selected channel (0–7).
* Returns a 10-bit result between 0 and 1023.
5. **Joystick Direction Input**
.. code-block:: python
def get_joystick_value():
x_val = read_adc(1)
y_val = read_adc(2)
if x_val > 800:
return 1
elif x_val < 200:
return -1
elif y_val > 800:
return -10
elif y_val < 200:
return 10
else:
return 0
* Reads horizontal (X) and vertical (Y) joystick movement and translates that into a change in threshold:
* Up/Down adjusts by 10.
* Left/Right adjusts by 1.
6. **Adjust Temperature Threshold**
.. code-block:: python
def upper_tem_setting():
global upperTem
LCD1602.write(0, 0, 'Upper Adjust: ')
change = int(get_joystick_value())
upperTem += change
strUpperTem = str(upperTem)
LCD1602.write(0, 1, strUpperTem)
LCD1602.write(len(strUpperTem), 1, ' ')
time.sleep(0.1)
* Allows the user to change the ``upperTem`` threshold via joystick.
* Updates LCD to display the current threshold value.
7. **Calculate Temperature from Analog Sensor**
.. code-block:: python
def temperature():
analogVal = read_adc(0)
Vr = 3.3 * analogVal / 1023.0
if Vr == 0:
return 0
Rt = 10000.0 * (3.3 - Vr) / Vr
tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0)))
Cel = tempK - 273.15
return round(Cel, 2)
* Converts voltage reading to resistance, then uses the Steinhart-Hart equation to compute the temperature in Celsius.
8. **Monitoring Mode**
.. code-block:: python
def monitoring_temp():
global upperTem
Cel = temperature()
LCD1602.write(0, 0, 'Temp: ')
LCD1602.write(0, 1, 'Upper: ')
LCD1602.write(6, 0, str(Cel))
LCD1602.write(7, 1, str(upperTem))
time.sleep(0.1)
if Cel >= upperTem:
GPIO.output(BUZZER_PIN, GPIO.HIGH)
GPIO.output(LED_PIN, GPIO.HIGH)
else:
GPIO.output(BUZZER_PIN, GPIO.LOW)
GPIO.output(LED_PIN, GPIO.LOW)
* Displays the current temperature and threshold.
* Activates buzzer and LED if the current temperature exceeds the threshold.
9. **Main Loop**
.. code-block:: python
try:
lastState = GPIO.input(JOY_BTN_PIN)
stage = 0
while True:
currentState = GPIO.input(JOY_BTN_PIN)
if currentState == GPIO.HIGH and lastState == GPIO.LOW:
stage = (stage + 1) % 2
time.sleep(0.1)
LCD1602.clear()
lastState = currentState
if stage == 1:
upper_tem_setting()
else:
monitoring_temp()
* Uses joystick button press to toggle between:
* ``stage 0``: temperature monitoring
* ``stage 1``: threshold adjustment
10. **Cleanup on Exit**
.. code-block:: python
except KeyboardInterrupt:
pass
finally:
LCD1602.clear()
GPIO.cleanup()
spi.close()
* Ensures GPIO and LCD are reset on program termination (e.g., Ctrl+C).