Nota
Ciao, benvenuto nella Community SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci Raspberry Pi, Arduino ed ESP32 insieme ad altri appassionati.
Perché unirti?
Supporto esperto: Risolvi problemi post-vendita e sfide tecniche con l’aiuto della nostra community e del nostro team.
Impara e condividi: Scambia consigli e tutorial per migliorare le tue competenze.
Anteprime esclusive: Ottieni accesso anticipato agli annunci di nuovi prodotti e anteprime.
Sconti speciali: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
Promozioni festive e giveaway: Partecipa a giveaway e promozioni festive.
👉 Pronto a esplorare e creare con noi? Clicca [Qui] e unisciti oggi stesso!
3.1.4 Ventilatore Intelligente (MCP3008)
Nota
A seconda della versione del tuo kit, identifica se possiedi ADC0834 o MCP3008 e procedi con la sezione corrispondente.
Introduzione
In questo progetto utilizzeremo motori, pulsanti e termistori per realizzare un ventilatore intelligente manuale + automatico con velocità regolabile.
Componenti Necessari
In questo progetto abbiamo bisogno dei seguenti componenti.
Schema Elettrico
T-Board Name |
fisico |
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 |
Procedure Sperimentali
Passo 1: Monta il circuito.
Nota
Il modulo di alimentazione può utilizzare una batteria da 9V con il connettore per batteria 9V incluso nel kit. Inserisci il ponticello del modulo di alimentazione nella barra del bus 5V della breadboard.
Per utenti del linguaggio C
Passo 2: Entra nella cartella del codice.
cd ~/davinci-kit-for-raspberry-pi/c/3.1.4-2/
Passo 3: Compila.
gcc 3.1.4_SmartFan.c -o SmartFan -lwiringPi -lm
Passo 4: Esegui il file eseguibile.
./SmartFan
Quando il codice è in esecuzione, avvia il ventilatore premendo il pulsante. Ogni volta che lo premi, il livello di velocità aumenta o diminuisce di 1 grado. Ci sono 5 livelli di velocità: 0~4. Quando è impostato al 4° livello e premi il pulsante, il ventilatore si ferma con velocità 0.
Quando la temperatura aumenta o diminuisce di oltre 2℃, la velocità aumenta o diminuisce automaticamente di un livello.
Nota
Se non funziona dopo l’esecuzione o viene visualizzato l’errore: "wiringPi.h: No such file or directory", fai riferimento a Installare e Verificare WiringPi.
Codice
#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; // Bit di avvio
buffer[1] = (8 + channel) << 4; // Modalità a estremità singola e canale
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int risultato = ((buffer[1] & 3) << 8) | buffer[2];
return risultato;
}
int temperture()
{
int analogVal = read_ADC(0);
double Vr = 3.3 * analogVal / 1023.0; // Usa 3.3V come Vref per 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 fallito!\n");
return;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup fallito!\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;
}
Spiegazione del Codice
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Bit di avvio
buffer[1] = (8 + channel) << 4; // Modalità a estremità singola e canale
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int risultato = ((buffer[1] & 3) << 8) | buffer[2];
return risultato;
}
Questa funzione viene utilizzata per leggere l’ingresso analogico dall’MCP3008 sul canale specificato. Invia un comando SPI di 3 byte e restituisce un valore digitale a 10 bit compreso tra 0 e 1023.
int temperture()
{
int analogVal = read_ADC(0);
double Vr = 3.3 * analogVal / 1023.0; // Usa 3.3V come Vref per 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;
}
La funzione temperture() legge il segnale analogico del termistore tramite MCP3008,
calcola tensione e resistenza, quindi converte in gradi Celsius e Fahrenheit utilizzando
la formula del termistore (approssimazione di Steinhart–Hart).
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;
}
La funzione motor() controlla la velocità della ventola tramite PWM.
Il livello varia da 0 a 4, dove 0 spegne la ventola e ogni livello aumenta il duty cycle del 25%.
void setup()
{
if (wiringPiSetup() == -1) {
printf("wiringPi setup fallito!\n");
return;
}
if (wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1) {
printf("SPI setup fallito!\n");
return;
}
softPwmCreate(MotorPin1, 0, 100);
softPwmCreate(MotorPin2, 0, 100);
pinMode(MotorEnable, OUTPUT);
pinMode(BtnPin, INPUT);
}
La funzione setup() inizializza WiringPi, configura l’SPI, imposta il PWM
e i pin GPIO necessari per il controllo del motore e l’ingresso del pulsante.
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;
}
La funzione main() contiene il ciclo principale del programma:
Controlla costantemente lo stato del pulsante e legge la temperatura corrente.
Alla pressione del pulsante, il livello della ventola aumenta (ciclicamente 0–4) e salva la temperatura.
Se la temperatura cambia di ±2°C, regola automaticamente la velocità della ventola.
Chiama
motor(level)per aggiornare l’uscita PWM in base al livello corrente.
Per gli Utenti del Linguaggio Python
Passo 2: Configura l’interfaccia SPI e installa la libreria spidev (vedi Configurazione SPI per le istruzioni dettagliate). Se hai già completato questi passaggi, puoi saltare oltre.
Passo 3: Vai nella cartella del codice.
cd ~/davinci-kit-for-raspberry-pi/python
Passo 4: Esegui.
sudo python3 3.1.4-2_SmartFan.py
Quando il codice è in esecuzione, avvia la ventola premendo il pulsante. Ogni volta che lo premi, la velocità viene aumentata o diminuita di 1 livello. Ci sono 5 livelli di velocità: 0~4. Quando è impostato sul 4° livello e premi il pulsante, la ventola si ferma con velocità 0.
Quando la temperatura sale o scende di oltre 2℃, la velocità aumenta o diminuisce automaticamente di 1 livello.
Codice
Nota
Puoi Modificare/Reimpostare/Copiare/Eseguire/Interrompere il codice qui sotto.
Ma prima di tutto, devi posizionarti nel percorso del codice sorgente, ad esempio davinci-kit-for-raspberry-pi/python.
Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l’effetto.
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
# Configurazione dei pin
BTN_PIN = 22 # Pulsante GPIO (pin fisico 15)
MOTOR_IN1 = 5 # Avanti
MOTOR_IN2 = 6 # Indietro
MOTOR_EN = 13 # Pin PWM
# Impostazione GPIO
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)
# Impostazione PWM per il controllo della velocità
pwm = GPIO.PWM(MOTOR_EN, 1000) # Frequenza 1 kHz
pwm.start(0)
# Inizializzazione SPI per MCP3008
spi = spidev.SpiDev()
spi.open(0, 0) # Bus 0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
# Variabili globali
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) # Mappa livello (1–4) a 25%–100%
return level
def changeLevel(channel):
global level, currentTemp, markTemp
print("Pulsante premuto")
level = (level + 1) % 5
markTemp = currentTemp
# Rilevamento evento pressione pulsante
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()
Spiegazione del Codice
Importa i moduli necessari:
RPi.GPIOper il controllo dei GPIO (pulsante e motore),spidevper comunicare con l’ADC MCP3008,timeper gestire i ritardi,mathper il calcolo della temperatura con funzioni logaritmiche.
import RPi.GPIO as GPIO import spidev import time import math
Configura i pin GPIO:
Pulsante su GPIO22 (con pull-up interno),
Controllo motore su GPIO5 (avanti), GPIO6 (indietro) e GPIO13 (PWM).
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)
Inizializza la comunicazione SPI verso MCP3008 (Bus 0, CE0) a 1 MHz.
spi = spidev.SpiDev() spi.open(0, 0) spi.max_speed_hz = 1000000
Definisce
read_adc()per leggere un valore analogico a 10 bit (0–1023) dal canale MCP3008 (0–7).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
Definisce
temperature()per:Convertire la tensione analogica in resistenza,
Applicare l’equazione di Steinhart–Hart per ottenere la temperatura in °C.
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
Definisce
motor_run()per:Fermare il motore a livello 0,
Far girare il motore in avanti con velocità crescente (livelli 1–4) mappati su duty cycle PWM dal 25% al 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
Definisce
changeLevel()come callback del pulsante per:Incrementare ciclicamente il livello del motore (0–4),
Registrare la temperatura attuale come nuova temperatura di riferimento.
def changeLevel(channel): global level, currentTemp, markTemp print("Pulsante premuto") level = (level + 1) % 5 markTemp = currentTemp GPIO.add_event_detect(BTN_PIN, GPIO.FALLING, callback=changeLevel, bouncetime=300)
Definisce il ciclo
main()per:Monitorare la variazione di temperatura rispetto al riferimento,
Diminuire il livello se la temperatura scende di 2°C o più,
Aumentare il livello se la temperatura sale di 2°C o più,
Regolare la velocità del motore ogni 0,2 secondi.
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)
Avvia la funzione principale e assicura la corretta pulizia delle risorse con Ctrl+C (ferma motore, pulisce GPIO, chiude SPI).
try: main() except KeyboardInterrupt: pass finally: pwm.stop() GPIO.cleanup() spi.close()