.. note::
Bonjour et bienvenue dans la communauté des passionnés de SunFounder Raspberry Pi & Arduino & ESP32 sur Facebook ! Plongez plus profondément dans l'univers du Raspberry Pi, de l'Arduino et de l'ESP32 avec d'autres passionnés.
**Pourquoi nous rejoindre ?**
- **Support d’experts** : Résolvez les problèmes après-vente et les défis techniques avec l’aide de notre communauté et de notre équipe.
- **Apprendre & Partager** : Échangez des astuces et tutoriels pour améliorer vos compétences.
- **Aperçus exclusifs** : Accédez en avant-première aux annonces de nouveaux produits et aperçus.
- **Réductions spéciales** : Profitez de réductions exclusives sur nos derniers produits.
- **Promotions festives et concours** : Participez à des concours et promotions spéciales pendant les fêtes.
👉 Prêt à explorer et créer avec nous ? Cliquez sur [|link_sf_facebook|] et rejoignez-nous dès aujourd'hui !
.. _3.1.4_c_mcp3008:
3.1.4 Ventilateur intelligent (MCP3008)
=======================================
.. note::
.. image:: img/mcp3008_and_adc0834.jpg
:width: 25%
:align: left
Selon la version de votre kit, identifiez si vous disposez de **l’ADC0834** ou du **MCP3008** et poursuivez avec la section correspondante.
Introduction
------------
Dans ce projet, nous utiliserons des moteurs, des boutons et des thermistances pour créer un ventilateur intelligent, manuel + automatique, dont la vitesse est réglable.
Composants requis
-----------------
Pour ce projet, nous avons besoin des composants suivants.
.. image:: img/list2_Smart_Fan.png
:align: center
Schéma de câblage
-----------------
============ ======== ======== ===
Nom T-Board physique 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
Procédure expérimentale
-----------------------
**Étape 1 :** Construire le circuit.
.. image:: img/july24_3.1.4_smart_fan_mcp3008.png
:align: center
.. note::
Le module d'alimentation peut utiliser une pile 9V avec le clip pour pile 9V fourni dans le kit. Insérez le cavalier du module d'alimentation dans les rails d'alimentation 5V de la plaque d’essai.
.. image:: img/image118.jpeg
:align: center
**Pour les utilisateurs du langage C**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Étape 2 :** Accédez au dossier du code.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/c/3.1.4-2/
**Étape 3 :** Compiler.
.. raw:: html
.. code-block::
gcc 3.1.4_SmartFan.c -o SmartFan -lwiringPi -lm
**Étape 4 :** Exécuter l’exécutable ci-dessus.
.. raw:: html
.. code-block::
./SmartFan
Lorsque le code s’exécute, démarrez le ventilateur en appuyant sur le bouton. Chaque pression augmente ou diminue le niveau de vitesse d’une unité.
Il y a **5** niveaux de vitesse : **0~4**. Lorsque vous atteignez le 4\ :sup:`ème` niveau et appuyez à nouveau, le ventilateur s'arrête (**0**).
Une variation de température supérieure à ±2℃ entraîne automatiquement une augmentation ou diminution d’un niveau de vitesse.
.. note::
Si le programme ne fonctionne pas après exécution ou si un message d'erreur apparaît : « wiringPi.h: No such file or directory », veuillez vous référer à :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; // Bit de démarrage
buffer[1] = (8 + channel) << 4; // Mode à extrémité unique et canal
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; // Utiliser 3,3V comme Vref pour 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;
}
Explication du code
----------------------
.. code-block:: c
int read_ADC(int channel)
{
if (channel < 0 || channel > 7) return -1;
unsigned char buffer[3];
buffer[0] = 1; // Bit de démarrage
buffer[1] = (8 + channel) << 4; // Mode unipolaire et canal
buffer[2] = 0;
wiringPiSPIDataRW(SPI_CHANNEL, buffer, 3);
int result = ((buffer[1] & 3) << 8) | buffer[2];
return result;
}
Cette fonction permet de lire une entrée analogique depuis le MCP3008 sur le canal spécifié.
Elle envoie une commande SPI de 3 octets et retourne une valeur numérique 10 bits comprise entre 0 et 1023.
.. code-block:: c
int temperture()
{
int analogVal = read_ADC(0);
double Vr = 3.3 * analogVal / 1023.0; // Utiliser 3,3 V comme Vref pour le 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 fonction ``temperture()`` lit le signal analogique du thermistor via le MCP3008,
calcule la tension et la résistance, puis convertit la valeur en Celsius et en Fahrenheit en utilisant
la formule du thermistor (approximation Steinhart–Hart).
.. 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;
}
La fonction ``motor()`` contrôle la vitesse du ventilateur via PWM.
Le niveau varie de 0 à 4, où 0 arrête le ventilateur et chaque niveau augmente le cycle de service de 25 %.
.. 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);
}
La fonction ``setup()`` initialise WiringPi, configure l’interface SPI, configure le PWM
et définit les broches GPIO nécessaires au contrôle du moteur et à l’entrée du bouton.
.. 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;
}
La fonction ``main()`` contient la boucle principale du programme :
1. Vérifie en continu l’état du bouton et lit la température actuelle.
2. Lorsqu’on appuie sur le bouton, le niveau du ventilateur augmente (cycle de 0 à 4) et enregistre la température.
3. Si la température change de ± 2 °C, la vitesse du ventilateur s’ajuste automatiquement.
4. Appelle ``motor(level)`` pour mettre à jour la sortie PWM selon le niveau.
**Pour les utilisateurs du langage Python**
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Étape 2 :** Configurez l’interface SPI et installez la bibliothèque ``spidev`` (voir :ref:`spi_configuration` pour les instructions détaillées).
Si vous avez déjà effectué ces étapes, vous pouvez les ignorer.
**Étape 3** : Accédez au dossier contenant le code.
.. raw:: html
.. code-block::
cd ~/davinci-kit-for-raspberry-pi/python
**Étape 4** : Exécutez.
.. raw:: html
.. code-block::
sudo python3 3.1.4-2_SmartFan.py
Lorsque le code s’exécute, démarrez le ventilateur en appuyant sur le bouton.
Chaque pression change la vitesse d’un niveau. Il y a **5** niveaux possibles : **0 à 4**.
À la 4\ :sup:`ème` vitesse, une pression supplémentaire arrête le ventilateur (niveau **0**).
Dès que la température augmente ou diminue de plus de 2 °C, la vitesse s’ajuste automatiquement d’un niveau.
Code
--------
.. note::
Vous pouvez **Modifier/Réinitialiser/Copier/Exécuter/Arrêter** le code ci-dessous. Avant cela,
assurez-vous d’être dans le chemin du code source comme ``davinci-kit-for-raspberry-pi/python``.
Après modification, vous pouvez l’exécuter directement pour voir l’effet.
.. raw:: html
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
# Configuration des broches
BTN_PIN = 22 # Bouton GPIO (broche physique 15)
MOTOR_IN1 = 5 # Moteur avant
MOTOR_IN2 = 6 # Moteur arrière
MOTOR_EN = 13 # Broche d’activation PWM
# Configuration 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)
# Configuration PWM pour le contrôle de la vitesse du moteur
pwm = GPIO.PWM(MOTOR_EN, 1000) # Fréquence de 1 kHz
pwm.start(0)
# Initialisation SPI pour MCP3008
spi = spidev.SpiDev()
spi.open(0, 0) # Bus 0, CE0
spi.max_speed_hz = 1000000 # 1 MHz
# Variables globales
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) # Mapper le niveau (1–4) à 25 %–100 %
return level
def changeLevel(channel):
global level, currentTemp, markTemp
print("Bouton pressé")
level = (level + 1) % 5
markTemp = currentTemp
# Détection d’événement pour le bouton
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()
Explication du code
---------------------
#. **Importer les modules nécessaires** :
- ``RPi.GPIO`` pour le contrôle GPIO (bouton et moteur)
- ``spidev`` pour la communication avec l’ADC MCP3008
- ``time`` pour les temporisations
- ``math`` pour les calculs logarithmiques de température
.. code-block:: python
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import spidev
import time
import math
#. **Configurer les broches GPIO** :
- Bouton sur GPIO22 (avec résistance de tirage interne)
- Contrôle moteur : GPIO5 (avant), GPIO6 (arrière), GPIO13 (activation PWM)
.. 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)
#. **Initialiser la communication SPI** avec MCP3008 (Bus 0, CE0) à 1 MHz
.. code-block:: python
spi = spidev.SpiDev()
spi.open(0, 0)
spi.max_speed_hz = 1000000
#. **Définir ``read_adc()``** : lit une valeur analogique 10 bits (0–1023) sur le canal MCP3008
.. 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
#. **Définir ``temperature()``** : convertit la tension analogique en résistance, applique la formule du thermistor et retourne la température en Celsius
.. 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
#. **Définir ``motor_run()``** :
- Niveau 0 : arrêt du moteur
- Niveaux 1–4 : PWM de 25 % à 100 % (moteur avant)
.. 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
#. **Définir ``changeLevel()``** : fonction de rappel pour le bouton qui incrémente le niveau du moteur et enregistre la température de référence
.. 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)
#. **Boucle ``main()``** :
- Surveille les variations de température par rapport à la référence
- Ajuste automatiquement la vitesse si ± 2 °C
- Met à jour le moteur toutes les 0,2 s
.. 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)
#. **Nettoyage** à l’arrêt (Ctrl + C) : arrêt PWM, nettoyage GPIO, fermeture SPI
.. code-block:: python
try:
main()
except KeyboardInterrupt:
pass
finally:
pwm.stop()
GPIO.cleanup()
spi.close()