Bemerkung

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 [hier] und trete noch heute bei!

3.1.4 Intelligenter Ventilator (MCP3008)

Bemerkung

_images/mcp3008_and_adc0834.jpg

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:

_images/list2_Smart_Fan.png

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

_images/schematic_3.1.4_smart_fan_mcp3008.png

Experimentelle Schritte

Schritt 1: Baue die Schaltung auf.

_images/july24_3.1.4_smart_fan_mcp3008.png

Bemerkung

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.

_images/image1181.jpeg

Für C-Sprach-Nutzer

Schritt 2: Wechsle in den Code-Ordner.

cd ~/davinci-kit-for-raspberry-pi/c/3.1.4-2/

Schritt 3: Kompilieren.

gcc 3.1.4_SmartFan.c -o SmartFan -lwiringPi -lm

Schritt 4: Die erstellte ausführbare Datei ausführen.

./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.

Bemerkung

Falls es nach dem Start nicht funktioniert oder eine Fehlermeldung wie „wiringPi.h: No such file or directory“ erscheint, siehe Installieren und Überprüfen von WiringPi.

Code

#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <stdio.h>
#include <softPwm.h>
#include <math.h>

#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

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.

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.

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.

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.

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 SPI-Konfiguration). Falls bereits geschehen, überspringen.

Schritt 3: Wechsle in den Code-Ordner.

cd ~/davinci-kit-for-raspberry-pi/python

Schritt 4: Ausführen.

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

Bemerkung

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.

#!/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

  1. 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.

    #!/usr/bin/env python3
    
    import RPi.GPIO as GPIO
    import spidev
    import time
    import math
    
  2. GPIO-Pins einrichten:

    • Taster an GPIO22 (mit internem Pull-up),

    • Motorsteuerung über GPIO5 (vorwärts), GPIO6 (rückwärts) und GPIO13 (PWM enable).

    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)
    
  3. SPI-Kommunikation mit MCP3008 initialisieren (Bus 0, CE0, 1 MHz).

    spi = spidev.SpiDev()
    spi.open(0, 0)
    spi.max_speed_hz = 1000000
    
  4. read_adc()-Funktion definiert, um einen 10-Bit-Analogwert (0–1023) vom angegebenen Kanal (0–7) zu lesen.

    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
    
  5. temperature()-Funktion:

    • Wandelt die analoge Spannung in Widerstand um,

    • Nutzt die Steinhart–Hart-Gleichung, um die Temperatur in Celsius zu berechnen.

    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
    
  6. motor_run():

    • Stoppt den Motor bei Stufe 0,

    • Läuft vorwärts mit steigender Geschwindigkeit bei Stufen 1–4 (PWM 25 %–100 %).

    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
    
  7. changeLevel()-Callback für Tastendruck:

    • Erhöht die Stufe zyklisch (0–4),

    • Speichert die aktuelle Temperatur als neuen Referenzwert.

    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)
    
  8. main()-Schleife:

    • Überwacht Temperaturänderungen,

    • Passt Stufe bei ±2 ℃ Änderung automatisch an,

    • Aktualisiert die Motorgeschwindigkeit alle 0,2 Sekunden.

    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)
    
  9. Hauptfunktion starten und bei Ctrl+C ordnungsgemäß aufräumen (Motor stoppen, GPIO zurücksetzen, SPI schließen).

    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        pwm.stop()
        GPIO.cleanup()
        spi.close()