TP 4 — Les ventilateurs ======================= Objectifs --------- - commander une **charge de puissance** (un moteur) par un transistor et un PWM ; - choisir une fréquence de PWM adaptée à un moteur ; - constater, mesures à l'appui, **les limites d'un ventilateur à deux fils**, et en tirer la bonne solution ; - faire un **thermostat** en tout ou rien, avec hystérésis. Durée indicative : une séance de 3 h. Prérequis : :doc:`tp02_pwm`. Matériel : un ventilateur 5 V à deux fils, branché sur le connecteur ``VENTILO_2``. Ce qu'il faut savoir -------------------- Le circuit ~~~~~~~~~~ La carte a deux sorties de ventilateur, ``VENTILO_1`` (PB14, TIM12_CH1) et ``VENTILO_2`` (PB15, TIM12_CH2), sur des connecteurs JST XH. Le ventilateur est alimenté en +5 V et **commuté côté masse** par un transistor MOSFET : .. tikz:: Commande d'un ventilateur : le transistor coupe la masse ; la diode protège de la surtension du moteur. \draw (0,4) node[left]{+5 V} to[short, o-*] (2,4) to[generic, l_=ventilateur] (2,1.6) coordinate (d) -- (2,1.2) node[nmos, anchor=D] (q) {}; \node at (2,2.8) {\small M}; \node[right, font=\scriptsize] at (q.east) {AO3400A}; \draw (q.S) node[ground]{}; \draw (d) to[short, *-] (4.4,1.6) to[D, l_={SS14}] (4.4,4) -- (2,4); \draw (q.G) -- ++(-0.6,0) coordinate (g) to[R, l_=$100\,\Omega$] ++(-2.2,0) to[short, -o] ++(-0.4,0) node[left]{PB15 (TIM12\_CH2)}; \draw (g) to[R, l_=$10\,\mathrm{k}\Omega$, *-] ++(0,-1.5) node[ground]{}; \node[font=\scriptsize, align=left, anchor=west, text width=3.8cm] at (6.0,2.8) {diode de roue libre : quand le transistor coupe, le courant du moteur continue de circuler par elle, sans surtension}; La **diode de roue libre** protège le transistor : un moteur est une bobine, et une bobine dont on coupe brutalement le courant produit une surtension. La diode offre au courant un chemin pour s'éteindre doucement. Pourquoi 25 kHz ~~~~~~~~~~~~~~~ Un moteur découpé à une fréquence audible **siffle**. On choisit donc une fréquence au-dessus de l'audible : **25 kHz**, la valeur normalisée des ventilateurs d'ordinateur. Avec l'horloge HSI à 64 MHz, TIM12 compte à 64 MHz : prédiviseur 0, période 2 559 donnent exactement 25 kHz. Étape 1 — Le ventilateur en PWM ------------------------------- #. Créez un projet ``tp04_ventilateurs`` comme au TP 1 (STM32H750VBTx, **SYS → Debug : Serial Wire**, horloge par défaut). #. Cliquez sur **PB15** et choisissez **TIM12_CH2**. Dans **Timers → TIM12**, réglez **Channel2** sur **PWM Generation CH2**, **Prescaler** 0, **Counter Period** 2559. #. Générez le code, démarrez le PWM, et faites tourner le ventilateur à 100 % (comparaison = 2 560). #. Descendez par paliers de 5 %, en restant 5 s sur chaque palier. Notez à quel rapport cyclique le ventilateur **ralentit**, et à quel rapport il **s'arrête**. .. Capture d'écran à insérer : CubeMX, TIM12 : Channel2 en PWM Generation CH2, Prescaler 0, Counter Period 2559. Déposez _static/captures/sans_os/tp04-tim12.png puis décommentez le bloc ci-dessous (retirez le préfixe « .. » devant chaque ligne) : .. .. image:: ../_static/captures/sans_os/tp04-tim12.png .. :align: center .. :width: 90% .. admonition:: Questions 1. Vérifiez par le calcul la fréquence de 25 kHz. 2. Le ventilateur ralentit-il progressivement ? À quel rapport cyclique s'arrête-t-il ? 3. Relancez-le à 100 % pendant une seconde, puis passez directement à 70 % : continue-t-il de tourner ? .. dropdown:: Solution de l'étape 1 :icon: code :color: secondary Une fonction règle le rapport cyclique en pourcentage (``USER CODE BEGIN 0``) : .. code-block:: c #define FAN_PERIOD 2560u /* ARR + 1 */ static void fan_set_pct(uint32_t pct) { if (pct > 100u) { pct = 100u; } /* borne : jamais plus de 100 % */ __HAL_TIM_SET_COMPARE(&htim12, TIM_CHANNEL_2, (FAN_PERIOD * pct) / 100u); } Dans ``USER CODE BEGIN 2`` : ``HAL_TIM_PWM_Start(&htim12, TIM_CHANNEL_2);``. Dans la boucle, la descente par paliers : .. code-block:: c for (int32_t p = 100; p >= 0; p -= 5) { fan_set_pct((uint32_t)p); HAL_Delay(5000); } **100 % = CCR 2 560, et non 2 559.** La sortie est à 1 tant que le compteur est **strictement** sous CCR. Le compteur va de 0 à 2 559 : avec CCR = 2 559, il passe un pas à 0 par période (99,96 %) ; avec CCR = 2 560, jamais — la sortie reste à 1 en permanence, un vrai 100 %. **L'ordre des opérations.** ``(2560 × pct) / 100`` multiplie avant de diviser : en entiers, ``2560 / 100 × pct`` donnerait 25 × pct, soit 2 500 à 100 % au lieu de 2 560, à cause de la troncature de la division. Pour suivre le palier courant sans terminal, on peut le ranger dans une variable globale ``volatile`` et la lire dans le débogueur (fenêtre **Live Expressions** de CubeIDE). .. dropdown:: Réponses aux questions 1 à 3 :icon: light-bulb :color: info **1. La fréquence.** TIM12 reçoit 64 MHz ; PSC = 0 ne divise pas ; le compteur fait 2 560 pas par période : .. code-block:: text f = 64 000 000 / ((0 + 1) × (2 559 + 1)) = 25 000 Hz période : 40 µs La résolution est de 2 560 pas, soit 0,04 % : bien plus fin que nécessaire. **2. Le comportement.** Non, il ne ralentit pas progressivement : il garde sa vitesse jusqu'à un certain rapport cyclique, puis **cale d'un coup**. Sur le ventilateur des robots, c'est dès **95 %**. Selon le modèle, le seuil peut être un peu plus bas, mais on n'obtient jamais une plage de vitesses réglable. **3. Après un démarrage à 100 %.** Il ne continue pas : même lancé à pleine vitesse, il cale à 70 %. Ce n'est donc **pas** un problème de couple au démarrage (qui serait réglé par l'élan) : quelque chose dans le ventilateur ne supporte pas le découpage lui-même. L'étape 2 explique quoi. Étape 2 — Comprendre ce qui se passe ------------------------------------ Un ventilateur à deux fils n'est pas un simple moteur : il contient une petite **électronique de commutation**, qui fait tourner son moteur sans balais. Elle est alimentée **par les deux mêmes fils** que le moteur. En découpant la masse, le PWM coupe aussi l'alimentation de cette électronique, des milliers de fois par seconde : elle décroche, et le ventilateur s'arrête bien avant que le rapport cyclique ne soit faible. Sur les cartes RatBot, le ventilateur à deux fils mesuré tourne à 100 %, et **cale dès 95 %**, même après un démarrage à pleine vitesse. La vitesse d'un tel ventilateur ne se règle pas par découpage de son alimentation. .. admonition:: Questions 4. Vos mesures confirment-elles ce comportement ? Votre ventilateur se comporte-t-il exactement de la même façon ? Pourquoi un autre modèle pourrait-il tenir un peu plus bas ? 5. Un ventilateur **à quatre fils** a une entrée dédiée au PWM, séparée de son alimentation. Pourquoi règle-t-il ce problème ? .. dropdown:: Réponses aux questions 4 et 5 :icon: light-bulb :color: info **4. Pourquoi ça cale.** Un ventilateur à deux fils contient un moteur **sans balais** : ses bobines sont commutées par un petit circuit (un capteur à effet Hall et un pilote), qui tire son alimentation des **mêmes deux fils**. Quand le transistor coupe la masse, 25 000 fois par seconde, ce circuit perd son alimentation à chaque coupure. Il tient tant que les coupures sont très brèves, grâce au petit condensateur qu'il a en interne ; au-delà, il redémarre sans cesse et perd le fil de la commutation : le moteur s'arrête. Le seuil dépend donc de la **réserve d'énergie** de ce circuit (la taille de son condensateur, sa consommation), qui varie d'un modèle à l'autre : un autre ventilateur pourra tenir à 80 %, mais aucun ne se réglera vraiment. **5. Le ventilateur à quatre fils.** Il a deux fils d'alimentation **permanente** (+12 V ou +5 V, et masse), un fil de vitesse mesurée (tachymètre), et un fil d'**entrée PWM**, qui n'alimente rien : c'est une simple consigne, lue par son électronique. Celle-ci reste alimentée en continu, et règle elle-même le courant du moteur. Le PWM n'est plus de la puissance, mais de l'**information**. Étape 3 — Un thermostat ----------------------- Puisque le ventilateur à deux fils ne se règle pas, on le commande **en tout ou rien**, d'après la température de la carte (TMP102, voir :doc:`tp07_i2c`) : #. Ajoutez la lecture du TMP102 (I2C2), une fois par seconde. #. Ventilateur en marche au-dessus de 35 °C, arrêté en dessous de 32 °C. .. admonition:: Question 6. Pourquoi deux seuils, et non un seul à 33,5 °C ? Que se passerait-il avec un seul seuil, quand la température est juste à cette valeur ? .. dropdown:: Solution de l'étape 3 :icon: code :color: secondary Il faut **I2C2** (PB10, PB11) en plus, configuré comme au TP 7. La lecture du TMP102 (``USER CODE BEGIN 0``) : .. code-block:: c #define TMP102_ADDR (0x48u << 1) static int temp_read_mC(int32_t *out) { uint8_t b[2]; int32_t raw; if (HAL_I2C_Mem_Read(&hi2c2, TMP102_ADDR, 0x00u, I2C_MEMADD_SIZE_8BIT, b, 2u, 5u) != HAL_OK) { return 0; } raw = (int32_t)((((uint16_t)b[0] << 8) | b[1]) >> 4); /* 12 bits */ if (raw & 0x800) { raw -= 4096; } /* signe */ *out = (raw * 625) / 10; /* 0,0625 °C par pas */ return 1; } et le thermostat, dans la boucle : .. code-block:: c #define FAN_ON_mC 35000 #define FAN_OFF_mC 32000 static uint32_t fan_on = 0u; int32_t t; if (temp_read_mC(&t)) { if (!fan_on && (t >= FAN_ON_mC)) { fan_on = 1u; } else if (fan_on && (t <= FAN_OFF_mC)) { fan_on = 0u; } } fan_set_pct(fan_on ? 100u : 0u); HAL_Delay(1000); **Les températures en millièmes de degré**, dans des entiers : on évite les nombres à virgule, et 35 °C s'écrit 35 000 sans perte. Le détail de la conversion du TMP102 est expliqué au TP 7. **Si la lecture échoue**, on garde l'état précédent du ventilateur plutôt que de l'arrêter : une panne du capteur ne doit pas couper le refroidissement. Un vrai produit allumerait même le ventilateur par précaution. .. dropdown:: Réponse à la question 6 :icon: light-bulb :color: info **6. Deux seuils : l'hystérésis.** Avec un seul seuil à 33,5 °C, quand la température est juste à cette valeur, le **bruit de mesure** (le dernier bit du capteur vaut 0,0625 °C) et le ventilateur lui-même la font osciller de part et d'autre : le ventilateur démarrerait et s'arrêterait à chaque seconde. C'est le **pompage** : bruyant, et qui use le moteur. Avec deux seuils, il y a une **bande morte** de 3 °C : une fois lancé à 35 °C, le ventilateur ne s'arrête qu'à 32 °C, et la carte doit se réchauffer de 3 °C avant qu'il redémarre. Le thermostat a une **mémoire** : son état ne dépend pas seulement de la température, mais aussi de son état précédent. C'est le principe de tous les thermostats, et d'un composant électronique classique, le **trigger de Schmitt**. .. dropdown:: Tout le code de la correction :icon: download :color: secondary :download:`main_user_code.c <../../corrections/sans_os/tp04/main_user_code.c>` — compilé sans avertissement contre la HAL du STM32H7. Ce n'est **pas** un ``main.c`` complet : ce sont les extraits à placer dans les blocs ``USER CODE`` du ``main.c`` généré par CubeMX, chacun sous le commentaire qui indique son bloc. La boucle ``while (1)`` contient une variante par étape, encadrée par ``#if 0`` / ``#if 1`` : n'en activer **qu'une à la fois**. La configuration CubeMX attendue est rappelée en tête du fichier, et les réponses aux questions à la fin. Exercices supplémentaires ------------------------- Ces exercices n'ont pas de correction. - **Les deux sorties** : branchez un second ventilateur sur ``VENTILO_1`` (PB14, TIM12_CH1) et commandez-les indépendamment. - **Seuils au terminal** : réglez les deux seuils du thermostat par la liaison série (:doc:`tp05_uart`). - **Ventilateur à quatre fils** : si vous en avez un, alimentez-le en permanence et envoyez le PWM sur son entrée de commande. Relevez la plage de vitesse obtenue. Après le TP ----------- Pour rendre la carte au robot, voir :ref:`etat-ratbot`.