.. 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()