[Introduction]
La technologie des microcontrôleurs est une technologie grand public indispensable dans l’automatisation industrielle moderne, l’électronique, l’électrotechnique et l’Internet des objets (IoT). Alors que nos vies deviennent de plus en plus intelligentes, la technologie des microcontrôleurs a imprégné pratiquement tous les aspects de notre vie quotidienne, comme les cuiseurs à riz intelligents, les haut-parleurs intelligents, etc.
Dans cette optique, la série d'articles « Réapprendre le microcontrôleur 51 » vise à aider les débutants à se lancer dans la technologie des microcontrôleurs. Nous commencerons par la tâche la plus simple-allumer une seule LED-et progresserons progressivement vers la mise en œuvre de modules tels que les boutons de commande, l'écran LCD1602, les capteurs de température DS18B20 et DS1302 et la communication entre deux microcontrôleurs. Nous couvrirons également les protocoles de communication matériels tels que UART, I²C et SPI. En combinant ces concepts avec des techniques de programmation C, nous utiliserons des projets d'ingénierie réels pour illustrer les approches de programmation, vous permettant d'appliquer de manière flexible des pointeurs et des structures C pour réaliser une programmation modulaire.
Revenons maintenant au sujet principal : utiliser un microcontrôleur 51 pour contrôler une LED et créer un effet de lumière respiratoire.
[Comment fonctionnent les lumières respiratoires]
Voyons d'abord comment fonctionne un effet de lumière respiratoire.
Une lumière respiratoire s’éclaire progressivement puis s’atténue progressivement, répétant ce cycle d’une manière qui ressemble à une respiration. Cependant, étant donné que les broches d'un microcontrôleur ne peuvent produire qu'un 1 (activé) ou un 0 (off), comment obtenir un effet de transition progressive ?
Cela est dû à la persistance de la vision dans nos yeux. Lorsque nous regardons quelque chose, l’image formée par nos yeux persiste pendant 0,04 seconde (ce chiffre a été trouvé en ligne).
Si nous calculons sur la base de 0,04 seconde, cela équivaut à 40 ms. Par conséquent, lorsque la LED est allumée et éteinte pendant 20 ms chacune, elle apparaît à l’œil humain comme si elle était constamment allumée.

L'effet d'une LED clignotante pendant 20 ms et éteinte pendant 20 ms est-il le même que si elle reste allumée tout le temps ?
Haha, c'est définitivement différent. Lorsque la lumière alterne entre allumage et extinction toutes les 20 millisecondes, l’effet que nous constatons est plus faible que lorsqu’elle reste allumée en continu. Si nous supposons que la luminosité d'une lumière allumée en continu est de 100 %, alors la luminosité d'une lumière qui alterne entre l'allumage et l'extinction toutes les 20 millisecondes est de 50 %. Sur cette base, nous pouvons ajuster la luminosité de la LED.

À ce stade, nous pouvons régler la luminosité de la LED (en réglant la durée du niveau haut dans le cycle de 40 ms). C'est le principe derrière la méthode bien connue -PWM (Pulse width Modulation) de contrôle de la luminosité, et régler la durée du niveau élevé équivaut à ajuster le rapport cyclique (c'est-à-dire la durée du niveau élevé divisée par le cycle total : 20/40=50 %).
Ici, le facteur le plus important est ce rapport cyclique. Par exemple, si la période est de 20 ms, avec la LED alternant entre 10 ms allumée et 10 ms éteinte, la luminosité perçue est toujours de 50 % (c'est-à-dire que le rapport cyclique est de 10/20=50 %).
Voyons ensuite comment cela est implémenté dans le programme.
[Mise en œuvre du programme]
Allumer une LED
Tout d’abord, commençons par allumer une LED, puis nous mettrons progressivement en œuvre un effet de lumière respiratoire. Le matériel que nous utiliserons est le suivant :
| Conseil de développement | Carte de développement de formation sur microcontrôleur ZeroOne |
|---|---|
| Modèle de microcontrôleur | STC89C52 |
| Interface LED | Broche P4^4 |

D'après le schéma, nous pouvons voir que la LED est connectée à la broche P4^4 du microcontrôleur. Lorsque le microcontrôleur émet un 1, la LED s'allume ; lorsqu'il émet un 0, la LED s'éteint. Par conséquent, le programme pour allumer une LED est assez simple, comme indiqué ci-dessous :

Le programme pour allumer une LED est assez simple ; Je suis sûr que tout le monde sait comment le faire.
Réglage de la luminosité des LED
Ensuite, nous implémenterons une fonction qui nous permet d'ajuster la luminosité (c'est-à-dire d'ajuster le rapport cyclique), comme suit :

Définissez une variable statique `duty_cycle` pour stocker le rapport cyclique. Lorsque « flag » est égal à 1, le rapport cyclique augmente progressivement jusqu'à 255, puis définissez « flag » sur 0 et « duty_cycle » diminue progressivement de 255 à 0. Répétez ce cycle.
Haha, à ce stade, vous pourriez penser que la lumière respiratoire fonctionne déjà, mais ce n'est pas le cas. Si vous ne me croyez pas, essayez vous-même le code ci-dessus.
Alors, où est exactement le problème ?
Le problème réside dans notre appel direct à la fonction de réglage de la luminosité- `set_led_luminance()`. Cette fonction prend 40 ms pour terminer un cycle, ce qui signifie que le rapport cyclique ne peut pas être modifié pendant ces 40 ms ; sinon, le réglage de la luminosité ne fonctionnera pas. Jetons un autre regard sur la fonction `breath_led`. Après chaque appel à `set_led_luminance()` pour définir le rapport cyclique, il modifie immédiatement la valeur `duty_cycle` sans attendre 40 ms.
À ce stade, nous devons ajouter une minuterie logicielle pour mettre à jour la valeur « duty_cycle » après 40 ms. Le programme modifié est le suivant :

Remarque : La durée de la minuterie doit simplement être supérieure à 40 ms (ce qui signifie que la valeur de « s_breathCounter » doit être supérieure à 255), mais il est préférable de la définir sur un multiple du cycle. Par exemple, si notre cycle est de 255 (soit 256 valeurs de 0 à 255), nous pouvons le définir sur deux fois cette valeur : 256 * 2 - 1=511 (soit 512 valeurs de 0 à 511).
Et voilà -notre lampe respiratoire est terminée ! N'est-ce pas simple ? (* ̄︶ ̄)
La prochaine étape est la section bonus d'aujourd'hui.
Bien que nous ayons obtenu l'effet de lumière respiratoire, le code n'est pas assez concis ni assez élégant ;-il utilise un tas d'instructions if et else. Voyons si nous pouvons le simplifier davantage.
Tout d'abord, simplifions cette section de la fonction set_led_luminance(), comme le montre la figure ci-dessous.

Avant de simplifier cela, abordons un petit conseil sur C : l'opération ET au niveau du bit.

De là, nous savons que, qu’il s’agisse de 1 ou de 0, effectuer une opération ET au niveau du bit avec 0 donne 0.
Qu'il s'agisse de 1 ou de 0, l'exécution d'une opération AND au niveau du bit avec 1 donne la valeur d'origine.
Pour plus de commodité, nous utilisons la notation hexadécimale (préfixée par « 0x ») ; par exemple, 0xff correspond à 255 en décimal. Donc,
Lorsqu'un nombre inférieur ou égal à 0xff est associé à 0xff, le résultat est le nombre lui-même, comme indiqué ci-dessous.

Que se passe-t-il si vous effectuez une opération ET au niveau du bit entre un nombre supérieur à 0xff et 0xff ?

Le résultat est le reste lorsque ce nombre est divisé par (0xff + 1) (c'est-à-dire que le résultat est toujours compris entre 0 et 0xff).
Avec cette opération ET au niveau du bit, le code ci-dessus peut être simplifié en

De cette façon, la valeur de s_Counter sera toujours comprise entre 0x00 et 0xff.
De même, la minuterie logicielle de la fonction Breath_led ci-dessus peut également être simplifiée comme suit :

À la ligne 3, 0x1ff vaut 511 en décimal. La condition est vraie lorsque la valeur de s_breathCounter est (0x1ff+1), ou 512, car 512 & 0x1ff=0. Le point d'exclamation avant indique une opération NOT au niveau du bit (pour être précis, la condition est remplie lorsque la valeur de `s_breathCounter` est un multiple de 512 ; cela élimine le besoin de réinitialiser `s_breathCounter`. J'espère que cette explication est clair-veuillez y réfléchir). Si la condition est remplie, le rapport cyclique commence à augmenter ou à diminuer.
Mais le rapport cyclique n'est-il pas compris entre 0 et 255 ? Pourquoi la ligne 5 devient-elle également 0x1ff (511) ? Ne vous inquiétez pas-regardez la ligne 8. Nous soustrayons à nouveau 0xff, donc la plage du rapport cyclique reste de 0 à 255.
Les lignes 7 à 10 signifient : lorsque « duty_cycle > (0xff) », c'est-à-dire 256 à 511, soustraire 0xff équivaut à augmenter de 1 à 255, donc la luminosité augmente progressivement.
Quand duty_cycle<= 0xff, the duty_cycle increases from 0 to 255, while the set brightness is 255 - duty_cycle. This effectively decreases the brightness from 255 to 0, causing the light to gradually dim. This achieves the breathing light effect.
Haha, tu pensais que notre simplification était terminée ?
Non, non, non
En fait, les lignes 7 à 10 pourraient être encore simplifiées. C’est là que la fonction valeur absolue s’avère utile.
Quoi? Pourquoi utiliser la fonction valeur absolue ?
Regardez la ligne 10 : 0xff - duty_cycle est équivalent à duty_cycle - 0xff et prend ensuite la valeur absolue. Bon, voici le code simplifié :
La fonction macro pour prendre la valeur absolue est la suivante
Enfin, j'ai inclus l'intégralité du code simplifié ci-dessous

Qu'en penses-tu? N'est-ce pas simple ? (* ̄︶ ̄)




