.. note::
Hallo, willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Community auf Facebook! Tauche tiefer in Raspberry Pi, Arduino und ESP32 mit anderen Enthusiasten ein.
**Warum beitreten?**
- **Expertenunterstützung**: Löse Probleme nach dem Kauf und technische Herausforderungen mit Hilfe unserer Community und unseres Teams.
- **Lernen & Teilen**: Tausche Tipps und Tutorials aus, um deine Fähigkeiten zu verbessern.
- **Exklusive Vorschauen**: Erhalte frühzeitigen Zugang zu neuen Produktankündigungen und Vorschauen.
- **Sonderrabatte**: Genieße exklusive Rabatte auf unsere neuesten Produkte.
- **Festliche Aktionen und Verlosungen**: Nimm an Gewinnspielen und Feiertagsaktionen teil.
👉 Bereit, mit uns zu entdecken und zu kreieren? Klicke [|link_sf_facebook|] und trete noch heute bei!
.. _3.1.5_c_mcp3008:
3.1.5 Batterieanzeige (MCP3008)
==================================
.. note::
.. image:: img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
Je nach Version deines Kits überprüfe bitte, ob du **ADC0834** oder **MCP3008** hast, und fahre mit dem entsprechenden Abschnitt fort.
Einführung
--------------
In diesem Projekt erstellen wir ein Batterieanzeigegerät, das den Batteriestand visuell auf einer LED-Balkenanzeige darstellen kann.
.. warning::
Verwende keine Batterien, die mehr als 3,3V liefern, um eine Überlastung zu vermeiden, die den Chip oder den Raspberry Pi beschädigen könnte.
Benötigte Bauteile
------------------------------
Für dieses Projekt benötigen wir die folgenden Komponenten.
.. image:: img/list2_Battery_Indicator.png
:align: center
Schaltplan
-------------------
============ ======== ======== ===
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:: img/schematic_battery_indicator_mcp3008.png
:align: center
Experimentelle Schritte
-------------------------
**Schritt 1:** Baue die Schaltung auf.
.. image:: img/july24_3.1.5_battery_indicator_mcp3008.png
**Für C-Sprach-Nutzer**
^^^^^^^^^^^^^^^^^^^^^^^^^
**Schritt 2:** Gehe in den Code-Ordner.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/c/3.1.5-2/
**Schritt 3:** Kompiliere den Code.
.. raw:: html
.. code-block::
gcc 3.1.5_BatteryIndicator.c -lwiringPi
**Schritt 4:** Führe die erstellte Datei aus.
.. raw:: html
.. code-block::
sudo ./a.out
Nach dem Start des Programms verbinde den 3. Pin des MCP3008 und GND jeweils mit einem Kabel, und schließe sie dann an die beiden Pole einer Batterie an. Du wirst sehen, dass die entsprechende LED auf der LED-Balkenanzeige leuchtet und den Ladezustand anzeigt (Messbereich: 0–5V).
.. note::
Falls das Programm nach dem Start nicht funktioniert oder eine Fehlermeldung wie „wiringPi.h: No such file or directory“ erscheint, siehe :ref:`install_wiringpi`.
Code
--------
.. code-block:: c
#include
#include
#include
#define SPI_CHANNEL 0
#define SPI_SPEED 1000000 // 1MHz
#define VREF 3.3
int pins[10] = {6, 26, 27, 28, 29, 21, 22, 23, 24, 25};
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Startbit
buffer[1] = (8 + channel) << 4; // Single-Ended-Modus
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int value = ((buffer[1] & 3) << 8) | buffer[2];
return value;
}
void LedBarGraph(int value) {
for (int i = 0; i < 10; i++) {
if (i < value)
digitalWrite(pins[i], HIGH);
else
digitalWrite(pins[i],LOW);
}
}
int main(void)
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi failed!\n");
return 1;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup failed!\n");
return 1;
}
for (int i = 0; i < 10; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], HIGH);
}
while (1) {
int analogVal = read_ADC(0); // MCP3008 CH0
if (analogVal < 0) continue;
float voltage = analogVal * VREF / 1023.0;
int level = analogVal * 10 / 1024;
if (level > 10) level = 10;
LedBarGraph(level);
printf("ADC Value: %d\tVoltage: %.2f V\tLevel: %d\n", analogVal, voltage, level);
delay(200);
}
return 0;
}
Code-Erklärung
----------------------
.. code-block:: c
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Startbit
buffer[1] = (8 + channel) << 4; // Single-Ended-Modus, CH0~CH7
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int value = ((buffer[1] & 3) << 8) | buffer[2]; // 10-Bit-Ergebnis kombinieren
return value;
}
Diese Funktion liest analoge Werte vom MCP3008-ADC-Chip über SPI.
Der Parameter ``channel`` wählt einen der 8 Analogeingänge (CH0–CH7).
Der MCP3008 gibt einen 10-Bit-Digitalwert zwischen 0 und 1023 zurück, der die analoge Spannung repräsentiert.
.. code-block:: c
void LedBarGraph(int value) {
for (int i = 0; i < 10; i++) {
if (i < value)
digitalWrite(pins[i], HIGH); // LED einschalten (aktiv HIGH)
else
digitalWrite(pins[i], LOW); // LED ausschalten
}
}
Diese Funktion steuert eine 10-LED-Balkenanzeige.
Jede LED repräsentiert ein Zehntel des Spannungsbereichs.
Die LEDs werden der Reihe nach bis zum angegebenen Level eingeschaltet.
Hinweis: Diese Version geht davon aus, dass die Anoden der LEDs mit den GPIOs verbunden sind und die Kathoden mit GND (aktiv HIGH).
.. code-block:: c
int main(void)
{
if (wiringPiSetup() == -1) {
printf("setup wiringPi failed!\n");
return 1;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup failed!\n");
return 1;
}
for (int i = 0; i < 10; i++) {
pinMode(pins[i], OUTPUT);
digitalWrite(pins[i], HIGH); // Alle LEDs einschalten
}
while (1) {
int analogVal = read_ADC(0); // Spannung an CH0 lesen
if (analogVal < 0) continue;
float voltage = analogVal * VREF / 1023.0;
int level = analogVal * 10 / 1024; // Auf 0–10 umrechnen
if (level > 10) level = 10;
LedBarGraph(level); // Level auf LEDs anzeigen
printf("ADC Value: %d\tVoltage: %.2f V\tLevel: %d\n", analogVal, voltage, level);
delay(200); // Aktualisierungsrate: 5 Hz
}
return 0;
}
Hauptlogik:
- Initialisiert wiringPi und die SPI-Kommunikation.
- Setzt GPIO-Pins als Ausgänge für die 10-LED-Balkenanzeige.
- Liest kontinuierlich die analoge Spannung über den MCP3008 (CH0).
- Wandelt den Wert in eine Spannung um (``VREF = 3.3V``).
- Skaliert die Spannung auf ein Level von 0–10 und schaltet die entsprechenden LEDs ein.
- Gibt den Rohwert des ADC, die Spannung (in Volt) und den LED-Level über die serielle Konsole aus.
Dies dient als visuelle Batterieanzeige oder analoges Voltmeter.
**Für Python-Sprach-Nutzer**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Schritt 2:** Richte die SPI-Schnittstelle ein und installiere die ``spidev``-Bibliothek (siehe :ref:`spi_configuration` für detaillierte Anweisungen).
Falls du diese Schritte bereits ausgeführt hast, kannst du diesen Punkt überspringen.
**Schritt 3:** Gehe in den Code-Ordner.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python
**Schritt 4:** Führe die Datei aus.
.. raw:: html
.. code-block::
sudo python3 3.1.5-2_BatteryIndicator.py
Nach dem Start des Programms verbinde den 3. Pin des ADC0834 und GND jeweils mit einem Kabel und schließe sie dann an die beiden Pole einer Batterie an.
Du wirst sehen, dass die entsprechende LED auf der LED-Balkenanzeige leuchtet und den Ladezustand anzeigt (Messbereich: 0–5V).
.. warning::
Falls die Fehlermeldung ``RuntimeError: Cannot determine SOC peripheral base address`` erscheint, siehe :ref:`faq_soc`
**Code**
.. note::
Du kannst den Code unten **Ändern/Zurücksetzen/Kopieren/Ausführen/Stoppen**.
Vorher musst du jedoch in den Quellcode-Pfad wechseln, z. B. ``davinci-kit-for-raspberry-pi/python``.
Nach einer Änderung kannst du ihn direkt ausführen und das Ergebnis sehen.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
# GPIO-Pins, die mit den 10 LEDs verbunden sind (von links nach rechts)
led_pins = [25, 12, 16, 20, 21, 5, 6, 13, 19, 26] # BCM-Nummerierung
# GPIO-Setup
GPIO.setmode(GPIO.BCM)
for pin in led_pins:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.LOW)
# SPI initialisieren
spi = spidev.SpiDev()
spi.open(0, 0) # Bus 0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
# Wert von MCP3008-Kanal lesen
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
r = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((r[1] & 0x03) << 8) | r[2]
return value
# LED-Balkenanzeige entsprechend dem Wert steuern
def led_bar_graph(level):
for i, pin in enumerate(led_pins):
if i < level:
GPIO.output(pin, GPIO.HIGH)
else:
GPIO.output(pin, GPIO.LOW)
# Hauptschleife
try:
while True:
analog_val = read_adc(0) # Von MCP3008-Kanal 0 lesen
level = int(analog_val * 10 / 1023)
led_bar_graph(level)
print(f"ADC: {analog_val}, Level: {level}")
time.sleep(0.2)
except KeyboardInterrupt:
pass
finally:
for pin in led_pins:
GPIO.output(pin, GPIO.LOW)
GPIO.cleanup()
spi.close()
Code-Erklärung
--------------------
Dieses Programm liest die analoge Spannung von einem MCP3008-ADC und zeigt das Ergebnis über eine 10-LED-Balkenanzeige an einem Raspberry Pi (BCM-Pinlayout) an.
1. **Module importieren**
- ``RPi.GPIO`` steuert die GPIO-Pins des Raspberry Pi.
- ``spidev`` ermöglicht die Kommunikation mit dem MCP3008 über SPI.
- ``time`` stellt Warte-/Schlaf-Funktionen bereit.
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
2. **GPIO-Setup für LEDs**
Eine Liste mit 10 GPIO-Pins wird zur LED-Steuerung definiert.
Diese Pins werden als Ausgänge konfiguriert und zunächst auf LOW (aus) gesetzt.
.. code-block:: python
led_pins = [25, 12, 16, 20, 21, 5, 6, 13, 19, 26] # BCM
GPIO.setmode(GPIO.BCM)
for pin in led_pins:
GPIO.setup(pin, GPIO.OUT)
GPIO.output(pin, GPIO.LOW)
3. **SPI-Initialisierung**
Initialisiert SPI-Bus 0 und Chip-Enable 0 (CE0) zur Kommunikation mit MCP3008.
Die Übertragungsgeschwindigkeit wird auf 1 MHz gesetzt.
.. code-block:: python
spi = spidev.SpiDev()
spi.open(0, 0) # Bus 0, CE0
spi.max_speed_hz = 1000000
4. **ADC-Lesefunktion**
Liest einen analogen Wert von einem angegebenen MCP3008-Kanal (0–7).
Die Funktion sendet einen 3-Byte-SPI-Befehl und dekodiert das 10-Bit-Ergebnis.
.. code-block:: python
def read_adc(channel):
if channel < 0 or channel > 7:
return -1
r = spi.xfer2([1, (8 + channel) << 4, 0])
value = ((r[1] & 0x03) << 8) | r[2]
return value
5. **LED-Balkenanzeige-Funktion**
Schaltet LEDs entsprechend dem Pegel ein.
Wenn der Pegel 7 beträgt, leuchten die ersten 7 LEDs, der Rest bleibt aus.
.. code-block:: python
def led_bar_graph(level):
for i, pin in enumerate(led_pins):
if i < level:
GPIO.output(pin, GPIO.HIGH)
else:
GPIO.output(pin, GPIO.LOW)
6. **Hauptschleife**
Liest kontinuierlich den analogen Eingang von Kanal 0, skaliert das Ergebnis auf einen Wert von 0–10 und aktualisiert die LED-Anzeige entsprechend.
Gibt den ADC-Wert und den Level-Wert zur Kontrolle aus.
.. code-block:: python
try:
while True:
analog_val = read_adc(0)
level = int(analog_val * 10 / 1023)
led_bar_graph(level)
print(f"ADC: {analog_val}, Level: {level}")
time.sleep(0.2)
7. **Aufräumen beim Beenden**
Wenn ``Strg+C`` gedrückt wird, schaltet das Programm alle LEDs aus, setzt den GPIO-Zustand zurück und schließt die SPI-Schnittstelle.
.. code-block:: python
except KeyboardInterrupt:
pass
finally:
for pin in led_pins:
GPIO.output(pin, GPIO.LOW)
GPIO.cleanup()
spi.close()