.. note:: Hallo, willkommen in der SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasten-Community auf Facebook! Tauche tiefer ein in Raspberry Pi, Arduino und ESP32 zusammen mit anderen Enthusiasten. **Warum beitreten?** - **Experten-Support**: 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 erschaffen? Klicke auf [|link_sf_facebook|] und trete noch heute bei! .. _3.1.4_c_mcp3008: 3.1.4 Intelligenter Ventilator (MCP3008) ======================================== .. note:: .. image:: img/mcp3008_and_adc0834.jpg :width: 25% :align: left Abhängig von deiner Bausatzversion überprüfe bitte, ob du **ADC0834** oder **MCP3008** hast, und fahre mit dem entsprechenden Abschnitt fort. Einführung ---------- In diesem Projekt verwenden wir Motoren, Taster und Thermistoren, um einen manuellen + automatischen intelligenten Ventilator zu bauen, dessen Windgeschwindigkeit einstellbar ist. Benötigte Komponenten ---------------------- Für dieses Projekt benötigen wir die folgenden Komponenten: .. image:: img/list2_Smart_Fan.png :align: center Schaltplan ---------- ============ ======== ======== === T-Board Name Physisch wiringPi BCM SPICE0 Pin 24 10 8 SPIMOSI Pin 19 12 10 SPIMISO Pin 21 13 9 SPISCLK Pin 23 14 11 GPIO22 Pin 15 3 22 GPIO5 Pin 29 21 5 GPIO6 Pin 31 22 6 GPIO13 Pin 33 23 13 ============ ======== ======== === .. image:: img/schematic_3.1.4_smart_fan_mcp3008.png :align: center Experimentelle Schritte ----------------------- **Schritt 1:** Baue die Schaltung auf. .. image:: img/july24_3.1.4_smart_fan_mcp3008.png :align: center .. note:: Das Strommodul kann mit einer 9V-Batterie und dem im Kit enthaltenen 9V-Batterieclip betrieben werden. Stecke den Jumper des Strommoduls in die 5V-Leiste des Breadboards. .. image:: img/image118.jpeg :align: center **Für C-Sprach-Nutzer** ^^^^^^^^^^^^^^^^^^^^^^^ **Schritt 2:** Wechsle in den Code-Ordner. .. code-block:: cd ~/davinci-kit-for-raspberry-pi/c/3.1.4-2/ **Schritt 3:** Kompilieren. .. code-block:: gcc 3.1.4_SmartFan.c -o SmartFan -lwiringPi -lm **Schritt 4:** Die erstellte ausführbare Datei ausführen. .. code-block:: ./SmartFan Während der Code läuft, starte den Ventilator durch Drücken des Tasters. Jeder Tastendruck erhöht oder verringert die Stufe um 1. Es gibt **5** Stufen: **0~4**. Bei Stufe 4 und erneutem Drücken stoppt der Ventilator (Stufe **0**). Wenn sich die Temperatur um mehr als ±2 ℃ ändert, passt sich die Geschwindigkeit automatisch um eine Stufe an. .. note:: Falls es 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 #include #include #define SPI_CHANNEL 0 #define SPI_SPEED 1000000 #define MotorPin1 21 #define MotorPin2 22 #define MotorEnable 23 #define BtnPin 3 int read_ADC(int channel) { if (channel < 0 || channel > 7) return -1; unsigned char buffer[3]; buffer[0] = 1; // Start bit buffer[1] = (8 + channel) << 4; // Single-ended mode and channel buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int result = ((buffer[1] & 3) << 8) | buffer[2]; return result; } int temperture() { int analogVal = read_ADC(0); double Vr = 3.3 * analogVal / 1023.0; // Use 3.3V as Vref for MCP3008 double Rt = 10000.0 * Vr / (3.3 - Vr); double temp = 1 / (((log(Rt / 10000.0)) / 3950.0) + (1 / (273.15 + 25.0))); double cel = temp - 273.15; double Fah = cel * 1.8 + 32; printf("Celsius: %.2f C Fahrenheit: %.2f F\n", cel, Fah); return (int)cel; } int motor(int level) { if (level == 0) { digitalWrite(MotorEnable, LOW); return 0; } if (level >= 4) { level = 4; } digitalWrite(MotorEnable, HIGH); softPwmWrite(MotorPin1, level * 25); return level; } void setup() { if (wiringPiSetup() == -1) { printf("wiringPi setup failed!\n"); return; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("SPI setup failed!\n"); return; } softPwmCreate(MotorPin1, 0, 100); softPwmCreate(MotorPin2, 0, 100); pinMode(MotorEnable, OUTPUT); pinMode(BtnPin, INPUT); } int main(void) { setup(); int currentState, lastState = 0; int level = 0; int currentTemp, markTemp = 0; while (1) { currentState = digitalRead(BtnPin); currentTemp = temperture(); if (currentTemp <= 0) continue; if (currentState == 1 && lastState == 0) { level = (level + 1) % 5; markTemp = currentTemp; delay(500); } lastState = currentState; if (level != 0) { if (currentTemp - markTemp <= -2) { level = level - 1; markTemp = currentTemp; } if (currentTemp - markTemp >= 2) { level = level + 1; markTemp = currentTemp; } } level = motor(level); } 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; // Start bit buffer[1] = (8 + channel) << 4; // Single-ended mode and channel buffer[2] = 0; wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3); int result = ((buffer[1] & 3) << 8) | buffer[2]; return result; } Diese Funktion liest einen analogen Eingang des MCP3008 am angegebenen Kanal. Sie sendet einen 3-Byte-SPI-Befehl und gibt einen 10-Bit-Digitalwert zwischen 0–1023 zurück. .. code-block:: c int temperture() { int analogVal = read_ADC(0); double Vr = 3.3 * analogVal / 1023.0; // Use 3.3V as Vref for MCP3008 double Rt = 10000.0 * Vr / (3.3 - Vr); double temp = 1 / (((log(Rt / 10000.0)) / 3950.0) + (1 / (273.15 + 25.0))); double cel = temp - 273.15; double Fah = cel * 1.8 + 32; printf("Celsius: %.2f C Fahrenheit: %.2f F\n", cel, Fah); return (int)cel; } Die Funktion ``temperture()`` liest das analoge Signal des Thermistors über den MCP3008, berechnet Spannung und Widerstand und wandelt diese dann mit der Thermistor-Formel (Steinhart–Hart-Approximation) in Celsius und Fahrenheit um. .. code-block:: c int motor(int level) { if (level == 0) { digitalWrite(MotorEnable, LOW); return 0; } if (level >= 4) { level = 4; } digitalWrite(MotorEnable, HIGH); softPwmWrite(MotorPin1, level * 25); return level; } Die Funktion ``motor()`` steuert die Lüftergeschwindigkeit über PWM. Die Stufe reicht von 0–4, wobei 0 den Lüfter ausschaltet und jede Stufe den Tastgrad um 25 % erhöht. .. code-block:: c void setup() { if (wiringPiSetup() == -1) { printf("wiringPi setup failed!\n"); return; } if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) { printf("SPI setup failed!\n"); return; } softPwmCreate(MotorPin1, 0, 100); softPwmCreate(MotorPin2, 0, 100); pinMode(MotorEnable, OUTPUT); pinMode(BtnPin, INPUT); } Die Funktion ``setup()`` initialisiert WiringPi, richtet SPI ein und konfiguriert PWM sowie GPIO-Pins für Motorsteuerung und Tastereingabe. .. code-block:: c int main(void) { setup(); int currentState, lastState = 0; int level = 0; int currentTemp, markTemp = 0; while (1) { currentState = digitalRead(BtnPin); currentTemp = temperture(); if (currentTemp <= 0) continue; if (currentState == 1 && lastState == 0) { level = (level + 1) % 5; markTemp = currentTemp; delay(500); } lastState = currentState; if (level != 0) { if (currentTemp - markTemp <= -2) { level = level - 1; markTemp = currentTemp; } if (currentTemp - markTemp >= 2) { level = level + 1; markTemp = currentTemp; } } level = motor(level); } return 0; } Die Funktion ``main()`` enthält die Programmschleife: 1. Überprüft ständig den Tasterstatus und liest die aktuelle Temperatur. 2. Bei Tastendruck erhöht sich die Stufe (zyklisch 0–4) und die Temperatur wird gespeichert. 3. Wenn sich die Temperatur um ±2 ℃ ändert, wird die Lüftergeschwindigkeit automatisch angepasst. 4. Ruft ``motor(level)`` auf, um die PWM-Ausgabe entsprechend zu setzen. **Für Python-Sprach-Nutzer** ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Schritt 2:** SPI-Schnittstelle einrichten und ``spidev``-Bibliothek installieren (siehe :ref:`spi_configuration`). Falls bereits geschehen, überspringen. **Schritt 3:** Wechsle in den Code-Ordner. .. code-block:: cd ~/davinci-kit-for-raspberry-pi/python **Schritt 4:** Ausführen. .. code-block:: sudo python3 3.1.4-2_SmartFan.py Funktionsweise: Wie bei der C-Version wird der Lüfter über den Taster gesteuert, Temperaturänderungen um ±2 ℃ passen die Stufe automatisch an. Code ---- .. note:: Du kannst den Code unten **Ändern/Zurücksetzen/Kopieren/Ausführen/Stoppen**. Wechsle vorher in den Quellcodepfad ``davinci-kit-for-raspberry-pi/python``. Nach Änderungen kannst du ihn direkt ausführen, um den Effekt zu sehen. .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time import math # Pin configuration BTN_PIN = 22 # Button GPIO (physical pin 15) MOTOR_IN1 = 5 # Motor forward MOTOR_IN2 = 6 # Motor backward MOTOR_EN = 13 # PWM enable pin # GPIO setup GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(MOTOR_IN1, GPIO.OUT) GPIO.setup(MOTOR_IN2, GPIO.OUT) GPIO.setup(MOTOR_EN, GPIO.OUT) # PWM setup for motor speed control pwm = GPIO.PWM(MOTOR_EN, 1000) # 1kHz frequency pwm.start(0) # Initialize SPI for MCP3008 spi = spidev.SpiDev() spi.open(0, 0) # Bus 0, CE0 spi.max_speed_hz = 1000000 # 1 MHz # Global variables level = 0 currentTemp = 0 markTemp = 0 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 def temperature(): analogVal = read_adc(0) Vr = 3.3 * analogVal / 1023.0 Rt = 10000.0 * Vr / (3.3 - Vr) tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0))) Cel = tempK - 273.15 return Cel def motor_run(level): if level == 0: GPIO.output(MOTOR_IN1, GPIO.LOW) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(0) return 0 if level >= 4: level = 4 GPIO.output(MOTOR_IN1, GPIO.HIGH) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(level * 25) # Map level (1–4) to 25%–100% return level def changeLevel(channel): global level, currentTemp, markTemp print("Button pressed") level = (level + 1) % 5 markTemp = currentTemp # Add event detection for button press GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300) def main(): global level, currentTemp, markTemp markTemp = temperature() while True: currentTemp = temperature() if level != 0: if currentTemp - markTemp <= -2: level -= 1 markTemp = currentTemp elif currentTemp - markTemp >= 2: if level < 4: level += 1 markTemp = currentTemp level = motor_run(level) time.sleep(0.2) try: main() except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close() Code-Erklärung -------------- #. Notwendige Module importieren: - ``RPi.GPIO`` für GPIO-Steuerung (Taster und Motor), - ``spidev`` für die Kommunikation mit dem MCP3008 ADC, - ``time`` für Verzögerungen, - ``math`` für Temperaturberechnungen mit Logarithmusfunktionen. .. code-block:: python #!/usr/bin/env python3 import RPi.GPIO as GPIO import spidev import time import math #. GPIO-Pins einrichten: - Taster an GPIO22 (mit internem Pull-up), - Motorsteuerung über GPIO5 (vorwärts), GPIO6 (rückwärts) und GPIO13 (PWM enable). .. code-block:: python BTN_PIN = 22 MOTOR_IN1 = 5 MOTOR_IN2 = 6 MOTOR_EN = 13 GPIO.setmode(GPIO.BCM) GPIO.setup(BTN_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(MOTOR_IN1, GPIO.OUT) GPIO.setup(MOTOR_IN2, GPIO.OUT) GPIO.setup(MOTOR_EN, GPIO.OUT) pwm = GPIO.PWM(MOTOR_EN, 1000) pwm.start(0) #. SPI-Kommunikation mit MCP3008 initialisieren (Bus 0, CE0, 1 MHz). .. code-block:: python spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000 #. ``read_adc()``-Funktion definiert, um einen 10-Bit-Analogwert (0–1023) vom angegebenen Kanal (0–7) zu lesen. .. 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 #. ``temperature()``-Funktion: - Wandelt die analoge Spannung in Widerstand um, - Nutzt die Steinhart–Hart-Gleichung, um die Temperatur in Celsius zu berechnen. .. code-block:: python def temperature(): analogVal = read_adc(0) Vr = 3.3 * analogVal / 1023.0 Rt = 10000.0 * Vr / (3.3 - Vr) tempK = 1.0 / (((math.log(Rt / 10000.0)) / 3950.0) + (1.0 / (273.15 + 25.0))) Cel = tempK - 273.15 return Cel #. ``motor_run()``: - Stoppt den Motor bei Stufe 0, - Läuft vorwärts mit steigender Geschwindigkeit bei Stufen 1–4 (PWM 25 %–100 %). .. code-block:: python def motor_run(level): if level == 0: GPIO.output(MOTOR_IN1, GPIO.LOW) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(0) return 0 if level >= 4: level = 4 GPIO.output(MOTOR_IN1, GPIO.HIGH) GPIO.output(MOTOR_IN2, GPIO.LOW) pwm.ChangeDutyCycle(level * 25) return level #. ``changeLevel()``-Callback für Tastendruck: - Erhöht die Stufe zyklisch (0–4), - Speichert die aktuelle Temperatur als neuen Referenzwert. .. code-block:: python def changeLevel(channel): global level, currentTemp, markTemp print("Button pressed") level = (level + 1) % 5 markTemp = currentTemp GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300) #. ``main()``-Schleife: - Überwacht Temperaturänderungen, - Passt Stufe bei ±2 ℃ Änderung automatisch an, - Aktualisiert die Motorgeschwindigkeit alle 0,2 Sekunden. .. code-block:: python def main(): global level, currentTemp, markTemp markTemp = temperature() while True: currentTemp = temperature() if level != 0: if currentTemp - markTemp <= -2: level -= 1 markTemp = currentTemp elif currentTemp - markTemp >= 2: if level < 4: level += 1 markTemp = currentTemp level = motor_run(level) time.sleep(0.2) #. Hauptfunktion starten und bei ``Ctrl+C`` ordnungsgemäß aufräumen (Motor stoppen, GPIO zurücksetzen, SPI schließen). .. code-block:: python try: main() except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close()