[Uvod]
Mikrokrmilniška tehnologija je nepogrešljiva mainstream tehnologija v sodobni industrijski avtomatizaciji, elektroniki, elektrotehniki in internetu stvari (IoT). Ker naša življenja postajajo vse bolj pametna, je tehnologija mikrokrmilnikov prežela skoraj vse vidike našega vsakdanjega življenja, na primer v pametnih kuhalnikih riža, pametnih zvočnikih in še več.
S tem v mislih je serija člankov "Relearning the 51 Microcontroller" namenjena začetnikom, ki pomagajo začeti s tehnologijo mikrokrmilnikov. Začeli bomo z najpreprostejšo nalogo-vklopom ene LED-in postopoma napredovali do implementacije modulov, kot so gumbi za upravljanje, zaslon LCD1602, temperaturna tipala DS18B20 in DS1302 ter komunikacija med dvema mikrokontrolerjema. Pokrivali bomo tudi komunikacijske protokole strojne opreme, kot so UART, I²C in SPI. Z združevanjem teh konceptov s tehnikami programiranja C bomo uporabili inženirske-projekte iz resničnega sveta za ponazoritev programskih pristopov, kar vam bo omogočilo prilagodljivo uporabo kazalcev in struktur C za doseganje modularnega programiranja.
Zdaj pa se vrnimo k glavni temi: uporaba mikrokrmilnika 51 za nadzor LED in ustvarjanje učinka dihajoče svetlobe.
[Kako delujejo dihalne luči]
Najprej si poglejmo, kako deluje svetlobni učinek dihanja.
Dihalna lučka se postopoma osvetli in nato postopoma zatemni, pri čemer se ta cikel ponavlja na način, ki spominja na dihanje. Ker pa lahko zatiči mikrokrmilnika oddajajo le 1 (vklopljeno) ali 0 (izklopljeno), kako je mogoče doseči učinek postopnega prehoda?
To je posledica obstojnosti vida v naših očeh. Ko nekaj pogledamo, slika, ki jo tvorijo naše oči, traja 0,04 sekunde (to številko smo našli na spletu).
Če izračunamo na podlagi 0,04 sekunde, je to enako 40 ms. Zato, ko je LED dioda prižgana in izklopljena za 20 ms, se človeškemu očesu zdi, kot da nenehno sveti.

Ali je učinek, če lučka LED utripa 20 ms in izklopljena 20 ms, enak, kot če bi svetila ves čas?
Haha, vsekakor je drugače. Ko se svetloba izmenično vklopi in izklopi vsakih 20 milisekund, je učinek, ki ga vidimo, zatemnjen, kot če je prižgana neprekinjeno. Če predpostavimo, da je svetlost neprekinjeno prižgane luči 100 %, potem je svetlost luči, ki se izmenično prižiga in ugasne vsakih 20 milisekund, 50 %. Na podlagi tega lahko prilagodimo svetlost LED.

Na tej točki lahko prilagodimo svetlost LED (z nastavitvijo trajanja visoke ravni v ciklu 40 ms). To je načelo za -znano metodo nadzora svetlosti PWM (Pulse Width Modulation), nastavitev trajanja visoke ravni pa je enakovredna prilagoditvi delovnega cikla (tj. trajanje visoke ravni deljeno s skupnim ciklom: 20/40=50%).
Tu je najpomembnejši dejavnik ta delovni cikel. Na primer, če je obdobje 20 ms, pri čemer lučka LED izmenično 10 ms prižge in 10 ms izklopi, je zaznana svetlost še vedno 50 % (tj. delovni cikel je 10/20=50%).
Nato si poglejmo, kako je to implementirano v program.
[Izvajanje programa]
Vklop LED
Najprej začnimo z vklopom LED, nato pa bomo postopoma uvedli učinek dihajoče svetlobe. Strojna oprema, ki jo bomo uporabljali, je naslednja:
| Razvojni odbor | Razvojna plošča za usposabljanje mikrokrmilnikov ZeroOne |
|---|---|
| Model mikrokontrolerja | STC89C52 |
| LED vmesnik | Pin P4^4 |

Iz sheme lahko vidimo, da je LED priključena na pin P4^4 mikrokontrolerja. Ko mikrokrmilnik odda 1, se LED vklopi; ko oddaja 0, LED ugasne. Zato je program za vklop LED precej preprost, kot je prikazano spodaj:

Program za vklop LED je precej preprost; Prepričan sem, da vsi vedo, kako to storiti.
Prilagoditev svetlosti LED
Nato bomo implementirali funkcijo, ki nam omogoča prilagoditev svetlosti (tj. prilagoditev delovnega cikla), kot sledi:

Definirajte statično spremenljivko `duty_cycle` za shranjevanje delovnega cikla. Ko je `flag` 1, se delovni cikel postopoma poveča na 255, nato nastavite `flag` na 0 in `duty_cycle` se postopoma zmanjša z 255 na 0. Ponovite ta cikel.
Haha, na tej točki bi morda mislili, da dihalna lučka že deluje, vendar ni. Če mi ne verjamete, poskusite zgornjo kodo sami.
Torej, kje točno je problem?
Težava je v našem neposrednem klicu funkcije-nastavitve svetlosti `set_led_luminance()`. Ta funkcija potrebuje 40 ms za dokončanje enega cikla, kar pomeni, da delovnega cikla med temi 40 ms ni mogoče spremeniti; sicer nastavitev svetlosti ne bo delovala. Oglejmo si še enkrat funkcijo `breath_led`. Po vsakem klicu `set_led_luminance()` za nastavitev delovnega cikla takoj spremeni vrednost `duty_cycle`, ne da bi čakal 40 ms.
Na tej točki moramo dodati programski časovnik za posodobitev vrednosti `duty_cycle` po preteku 40 ms. Spremenjeni program je naslednji:

Opomba: trajanje časovnika mora biti daljše od 40 ms (kar pomeni, da mora biti vrednost `s_breathCounter` večja od 255), vendar je najbolje, da ga nastavite na večkratnik cikla. Na primer, če je naš cikel 255 (tj. 256 vrednosti od 0 do 255), ga lahko nastavimo na dvakrat večjo vrednost: 256 * 2 - 1=511 (tj. 512 vrednosti od 0 do 511).
In tukaj je-naša dihalna lučka je končana! Ali ni to preprosto? (* ̄︶ ̄)
Naslednji je današnji razdelek o bonusih.
Čeprav smo dosegli učinek dihajoče svetlobe, koda ni dovolj jedrnata ali elegantna-uporablja kup stavkov if in else. Poglejmo, ali ga lahko še poenostavimo.
Najprej poenostavimo ta del funkcije set_led_luminance(), kot je prikazano na spodnji sliki.

Preden to poenostavimo, si oglejmo hiter nasvet o C: bitni operaciji IN.

Iz tega vemo, da ne glede na to, ali je 1 ali 0, izvedba bitne operacije IN z 0 povzroči 0.
Ne glede na to, ali je 1 ali 0, izvedba bitne operacije IN z 1 povzroči prvotno vrednost.
Za udobje uporabljamo šestnajstiški zapis (s predpono "0x"); na primer 0xff ustreza 255 v decimalki. zato
Ko je število, ki je manjše ali enako 0xff, dodano IN z 0xff, je rezultat samo število, kot je prikazano spodaj

Kaj se zgodi, če izvedete bitno operacijo IN med številom, večjim od 0xff in 0xff?

Rezultat je ostanek, ko je to število deljeno z (0xff + 1) (tj. rezultat je še vedno med 0 in 0xff).
S to operacijo bitnega IN lahko zgornjo kodo poenostavimo na

Na ta način bo vrednost s_Counter vedno v območju od 0x00 do 0xff.
Podobno je mogoče programski časovnik v zgornji funkciji breath_led poenostaviti na naslednji način:

V vrstici 3 je 0x1ff 511 v decimalki. Pogoj je resničen, ko je vrednost s_breathCounter (0x1ff+1) ali 512, ker 512 & 0x1ff=0. Klicaj pred njim označuje operacijo bitnega NE (če smo natančni, je pogoj izpolnjen, ko je vrednost `s_breathCounter` večkratnik 512; to odpravlja potrebo po ponastavitvi `s_breathCounter` Upam, da je ta razlaga jasna-prosim, premislite). Če je pogoj izpolnjen, se delovni cikel začne povečevati ali zmanjševati.
Toda ali ni obseg delovnega cikla od 0 do 255? Zakaj tudi vrstica 5 postane 0x1ff (511)? Brez skrbi-poglejte vrstico 8. Ponovno odštejemo 0xff, tako da obseg delovnega cikla ostane od 0 do 255.
Vrstice 7–10 pomenijo: Ko je `duty_cycle > (0xff)`, tj. 256–511, je odštevanje 0xff enakovredno povečanju od 1 do 255, tako da se svetlost postopoma povečuje.
Ko je delovni_cikel<= 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, ste mislili, da je konec našega poenostavljanja?
Ne, ne, ne
Pravzaprav bi lahko vrstice od 7 do 10 še bolj poenostavili. Tukaj pride prav funkcija absolutne vrednosti.
Kaj? Zakaj uporabljati funkcijo absolutne vrednosti?
Poglejte vrstico 10: 0xff - duty_cycle je enakovreden duty_cycle - 0xff in nato vzame absolutno vrednost. V redu, tukaj je poenostavljena koda:
Makro funkcija za jemanje absolutne vrednosti je naslednja
Končno sem spodaj vključil celotno poenostavljeno kodo

kaj misliš Ali ni preprosto? (* ̄︶ ̄)




