[Introducció]
La tecnologia de microcontroladors és una tecnologia dominant indispensable en l'automatització industrial moderna, l'electrònica, l'enginyeria elèctrica i l'Internet de les coses (IoT). A mesura que les nostres vides són cada cop més intel·ligents, la tecnologia dels microcontroladors ha impregnat pràcticament tots els aspectes de la nostra vida diària, com ara les arrosseres intel·ligents, els altaveus intel·ligents i molt més.
Amb això en ment, la sèrie d'articles "Relearning the 51 Microcontroller" pretén ajudar els principiants a començar amb la tecnologia dels microcontroladors. Començarem amb la tasca més senzilla-encendre un únic LED-i progressivament avançarem cap a la implementació de mòduls com els controls de botons, la pantalla LCD1602, els sensors de temperatura DS18B20 i DS1302 i la comunicació entre dos microcontroladors. També cobrirem protocols de comunicació de maquinari com UART, I²C i SPI. En combinar aquests conceptes amb tècniques de programació en C, utilitzarem projectes d'enginyeria{10}}reals per il·lustrar els enfocaments de programació, cosa que us permetrà aplicar de manera flexible punters i estructures C per aconseguir una programació modular.
Ara, tornem al tema principal: utilitzar un microcontrolador 51 per controlar un LED i crear un efecte de llum respiratòria.
[Com funcionen els llums de respiració]
Vegem primer com funciona un efecte de llum respiratòria.
Una llum de respiració s'il·lumina gradualment i després s'atenua gradualment, repetint aquest cicle d'una manera que s'assembla a la respiració. Tanmateix, com que els pins d'un microcontrolador només poden sortir un 1 (activat) o un 0 (desactivat), com es pot aconseguir un efecte de transició gradual?
Això es deu a la persistència de la visió als nostres ulls. Quan mirem alguna cosa, la imatge formada pels nostres ulls persisteix durant 0,04 segons (aquesta xifra es va trobar en línia).
Si calculem a partir de 0,04 segons, això equival a 40 ms. Per tant, quan el LED està encès i apagat durant 20 ms cadascun, sembla a l'ull humà com si estigués constantment il·luminat.

L'efecte d'un LED parpellejant durant 20 ms i apagat durant 20 ms és el mateix que mantenir-lo encès tot el temps?
Haha, definitivament és diferent. Quan la llum alterna entre encendre i apagar cada 20 mil·lisegons, l'efecte que veiem és més tènue que quan es manté encès contínuament. Si suposem que la brillantor d'una llum encesa contínuament és del 100%, aleshores la brillantor d'una llum que s'alterna entre encendre i apagar cada 20 mil·lisegons és del 50%. En base a això, podem ajustar la brillantor del LED.

En aquest punt, podem ajustar la brillantor del LED (fixant la durada del nivell alt dins del cicle de 40 ms). Aquest és el principi darrere del conegut mètode PWM (modulació d'amplada de pols) de control de la brillantor, i establir la durada del nivell alt equival a ajustar el cicle de treball (és a dir, la durada del nivell alt dividida pel cicle total: 20/40=50%).
Aquí, el factor més important és aquest cicle de treball. Per exemple, si el període és de 20 ms, amb el LED alternant entre 10 ms encès i 10 ms apagat, la brillantor percebuda encara és del 50% (és a dir, el cicle de treball és del 10/20=50%).
A continuació, veurem com s'implementa això al programa.
[Implementació del programa]
Encendre un LED
Primer, comencem encendre un LED i, a poc a poc, implementarem un efecte de llum respiratòria. El maquinari que farem servir és el següent:
| Junta de Desenvolupament | Tauler de desenvolupament de formació de microcontroladors ZeroOne |
|---|---|
| Model de microcontrolador | STC89C52 |
| Interfície LED | Pin P4^4 |

A l'esquema, podem veure que el LED està connectat al pin P4 ^ 4 del microcontrolador. Quan el microcontrolador emet un 1, el LED s'encén; quan emet un 0, el LED s'apaga. Per tant, el programa per encendre un LED és bastant senzill, com es mostra a continuació:

El programa per encendre un LED és bastant senzill; Estic segur que tothom sap com fer-ho.
Ajust de la brillantor del LED
A continuació, implementarem una funció que ens permeti ajustar la brillantor (és a dir, ajustar el cicle de treball), de la següent manera:

Definiu una variable estàtica "duty_cycle" per emmagatzemar el cicle de treball. Quan "flag" és 1, el cicle de treball augmenta gradualment fins a 255, després estableix "flag" a 0 i "duty_cycle" disminueix gradualment de 255 a 0. Repetiu aquest cicle.
Haha, en aquest punt, podríeu pensar que la llum de respiració ja funciona, però no ho és. Si no em creus, prova el codi que hi ha a sobre.
Llavors, on és exactament el problema?
El problema rau en la nostra crida directa a la funció de configuració de-brillante `set_led_luminance()`. Aquesta funció triga 40 ms a completar un cicle, és a dir, el cicle de treball no es pot canviar durant aquests 40 ms; en cas contrari, l'ajust de la brillantor no funcionarà. Fem una altra ullada a la funció `breath_led`. Després de cada trucada a `set_led_luminance()` per establir el cicle de treball, canvia immediatament el valor de `duty_cycle` sense esperar 40 ms.
En aquest punt, hem d'afegir un temporitzador de programari per actualitzar el valor "duty_cycle" després que hagin transcorregut 40 ms. El programa modificat és el següent:

Nota: La durada del temporitzador només ha de ser superior a 40 ms (és a dir, el valor de `s_breathCounter` ha de ser superior a 255), però el millor és configurar-lo en un múltiple del cicle. Per exemple, si el nostre cicle és 255 (és a dir, 256 valors de 0 a 255), podem definir-lo al doble d'aquest valor: 256 * 2 - 1=511 (és a dir, 512 valors de 0 a 511).
I ja ho teniu-la nostra llum de respiració està completa! No és senzill? (* ̄︶ ̄)
El següent és la secció de bonificacions d'avui.
Tot i que hem aconseguit l'efecte de la llum respiratòria, el codi no és prou concís ni prou elegant-fa servir un munt de declaracions if i else. A veure si podem simplificar-ho més.
Primer, simplifiquem aquesta secció de la funció set_led_luminance(), tal com es mostra a la figura següent.

Abans de simplificar això, cobrim un consell ràpid sobre C: l'operació AND bit a bit.

A partir d'això, sabem que si és 1 o 0, realitzar una operació AND bit a bit amb 0 dóna com a resultat 0.
Tant si és 1 com 0, realitzar una operació AND bit a bit amb 1 dóna com a resultat el valor original.
Per comoditat, utilitzem la notació hexadecimal (prefixada amb "0x"); per exemple, 0xff correspon a 255 en decimal. Per tant,
Quan un nombre inferior o igual a 0xff es combina AND amb 0xff, el resultat és el nombre en si, tal com es mostra a continuació

Què passa si feu una operació AND bit a bit entre un nombre superior a 0xff i 0xff?

El resultat és la resta quan aquest nombre es divideix per (0xff + 1) (és a dir, el resultat encara està entre 0 i 0xff).
Amb aquesta operació AND bit a bit, el codi anterior es pot simplificar a

D'aquesta manera, el valor de s_Counter sempre estarà dins del rang de 0x00 a 0xff.
De la mateixa manera, el temporitzador de programari de la funció breath_led anterior també es pot simplificar de la següent manera:

A la línia 3, 0x1ff és 511 en decimal. La condició és certa quan el valor de s_breathCounter és (0x1ff+1), o 512, perquè 512 i 0x1ff=0. El signe d'exclamació abans indica una operació NOT per bits (per ser exactes, la condició es compleix quan el valor de `s_breathCounter` és un múltiple de 512; això elimina la necessitat de reiniciar 512). `s_breathCounter`. Espero que aquesta explicació sigui clara-pensa-ho bé). Si es compleix la condició, el cicle de treball comença a augmentar o disminuir.
Però el cicle de treball no és de 0 a 255? Per què la línia 5 també es converteix en 0x1ff (511)? No us preocupeu-mireu la línia 8. Restem 0xff de nou, de manera que l'interval del cicle de treball es manté entre 0 i 255.
Les línies 7–10 signifiquen: quan `duty_cycle > (0xff)`, és a dir, 256–511, restar 0xff equival a augmentar d'1 a 255, de manera que la brillantor augmenta gradualment.
Quan 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, creieu que s'havia acabat la nostra simplificació?
No, no, no
De fet, les línies 7 a 10 es podrien simplificar encara més. Aquí és on la funció de valor absolut és útil.
Què? Per què utilitzar la funció de valor absolut?
Mireu la línia 10: 0xff - duty_cycle és equivalent a duty_cycle - 0xff i després prenent el valor absolut. D'acord, aquí teniu el codi simplificat:
La funció macro per prendre el valor absolut és la següent
Finalment, he inclòs tot el codi simplificat a continuació

Què et sembla? No és senzill? (* ̄︶ ̄)




