Implementacija LED svjetla za disanje pomoću 51 mikrokontrolera

Jun 11, 2026 Ostavi poruku

[Uvod]


Tehnologija mikrokontrolera je nezamjenjiva glavna tehnologija u modernoj industrijskoj automatizaciji, elektronici, elektrotehnici i Internetu stvari (IoT). Kako naši životi postaju sve pametniji, tehnologija mikrokontrolera je prožela gotovo svaki aspekt našeg svakodnevnog života, kao što su pametni kuhala za rižu, pametni zvučnici i još mnogo toga.


Imajući to na umu, serija članaka "Ponovno učenje 51 mikrokontrolera" ima za cilj da pomogne početnicima da započnu sa tehnologijom mikrokontrolera. Počećemo sa najjednostavnijim zadatkom-uključivanjem jedne LED diode-i postepeno napredovati do implementacije modula kao što su kontrole dugmadi, LCD1602 displej, DS18B20 i DS1302 temperaturni senzori i komunikacija između dva mikrokontrolera. Također ćemo pokriti hardverske komunikacijske protokole kao što su UART, I²C i SPI. Kombinacijom ovih koncepata sa tehnikama C programiranja, koristit ćemo stvarne{10}}svjetske inženjerske projekte da ilustrujemo pristupe programiranju, omogućavajući vam da fleksibilno primjenjujete C pokazivače i strukture za postizanje modularnog programiranja.


Vratimo se sada na glavnu temu: korištenje 51 mikrokontrolera za upravljanje LED diodom i stvaranje efekta svjetlosti koji diše.

 

[Kako funkcioniraju svjetlo za disanje]


Hajde da prvo pogledamo kako funkcioniše svetlosni efekat disanja.
Svjetlo za disanje postepeno se pojačava, a zatim postepeno gasi, ponavljajući ovaj ciklus na način koji podsjeća na disanje. Međutim, budući da pinovi mikrokontrolera mogu da daju samo 1 (uključeno) ili 0 (isključeno), kako se može postići efekat postepenog prelaza?
To je zbog postojanosti vida u našim očima. Kada nešto pogledamo, slika koju formiraju naše oči traje 0,04 sekunde (ova brojka je pronađena na internetu).
Ako izračunamo na osnovu 0,04 sekunde, to je 40 ms. Stoga, kada je LED dioda uključena i isključena po 20 ms, ljudskom oku izgleda kao da stalno svijetli.

图片

Da li je efekat svetlećih LED dioda 20 ms i isključenih 20 ms isti kao da stalno svetli?

 

Haha, definitivno je drugačije. Kada se svjetlo naizmjenično uključuje i gasi svakih 20 milisekundi, efekat koji vidimo je prigušeniji nego kada ostaje neprekidno uključen. Ako pretpostavimo da je svjetlina neprekidno upaljenog svjetla 100%, tada je svjetlina svjetla koje se naizmjenično uključuje i gasi svakih 20 milisekundi 50%. Na osnovu toga možemo podesiti svjetlinu LED dioda.

图片

 

U ovom trenutku možemo podesiti svjetlinu LED-a (podešavanjem trajanja visokog nivoa unutar ciklusa od 40 ms). Ovo je princip iza dobro-poznatog PWM (Pulse Width Modulation) metode kontrole svjetline, a postavljanje trajanja visokog nivoa je ekvivalentno podešavanju radnog ciklusa (tj. trajanje visokog nivoa podijeljeno sa ukupnim ciklusom: 20/40=50%).


Ovdje je najvažniji faktor ovaj radni ciklus. Na primjer, ako je period 20 ms, sa LED diodom koja se naizmjenično uključuje između 10 ms i 10 ms isključena, percipirana svjetlina je i dalje 50% (tj. radni ciklus je 10/20=50%).

Dalje, da vidimo kako je to implementirano u programu.

 

[Implementacija programa]


Uključivanje LED-a
Prvo, počnimo s uključivanjem LED diode, a zatim ćemo postepeno implementirati svjetlosni efekat disanja. Hardver koji ćemo koristiti je sljedeći:

Odbor za razvoj ZeroOne Microcontroller Training Development Board
Model mikrokontrolera STC89C52
LED interfejs Pin P4^4
图片

 

Iz šeme možemo vidjeti da je LED spojen na pin P4^4 mikrokontrolera. Kada mikrokontroler da 1, LED se pali; kada proizvede 0, LED se gasi. Stoga je program za uključivanje LED-a prilično jednostavan, kao što je prikazano u nastavku:

info-299-230

 

 

Program za uključivanje LED-a je prilično jednostavan; Siguran sam da svi znaju kako se to radi.
 

Podešavanje svjetline LED dioda


Zatim ćemo implementirati funkciju koja nam omogućava da prilagodimo svjetlinu (tj. prilagodimo radni ciklus), kako slijedi:

info-400-538


 

Definirajte statičku varijablu `duty_cycle` za pohranjivanje radnog ciklusa. Kada je `flag` 1, radni ciklus se postepeno povećava na 255, zatim postavite `flag` na 0, a `duty_cycle` se postepeno smanjuje sa 255 na 0. Ponovite ovaj ciklus.
Haha, u ovom trenutku biste mogli pomisliti da svjetlo za disanje već radi, ali nije. Ako mi ne vjerujete, isprobajte kod iznad.

Dakle, gdje je tačno problem?


Problem leži u našem direktnom pozivu funkcije{0}}podešavanja svjetline `set_led_luminance()`. Ovoj funkciji je potrebno 40 ms da završi jedan ciklus, što znači da se radni ciklus ne može promijeniti tokom tih 40 ms; u suprotnom, podešavanje svjetline neće raditi. Pogledajmo još jednom funkciju `breath_led`. Nakon svakog poziva `set_led_luminance()` za postavljanje radnog ciklusa, on odmah mijenja vrijednost `duty_cycle` bez čekanja 40 ms.


U ovom trenutku moramo dodati softverski tajmer za ažuriranje vrijednosti `duty_cycle` nakon što prođe 40 ms. Modifikovani program je sledeći:

info-495-656

 

 

Napomena: Trajanje tajmera samo treba biti veće od 40 ms (što znači da vrijednost `s_breathCounter` mora biti veća od 255), ali je najbolje da ga postavite na višekratnik ciklusa. Na primjer, ako je naš ciklus 255 (tj. 256 vrijednosti od 0 do 255), možemo ga postaviti na dvostruko veću vrijednost: 256 * 2 - 1=511 (tj. 512 vrijednosti od 0 do 511).
I eto ga-naše svjetlo za disanje je kompletno! Nije li to jednostavno? (* ̄︶ ̄)

 

Sljedeći je današnji bonus dio.

Iako smo postigli efekat disanja svjetlosti, kod nije sasvim koncizan ili dovoljno elegantan-koristi gomilu if i else izjava. Hajde da vidimo možemo li to dodatno pojednostaviti.

Prvo, pojednostavimo ovaj dio funkcije set_led_luminance(), kao što je prikazano na slici ispod.
 

图片

 

Prije nego što ovo pojednostavimo, pokrijmo kratak savjet o C: operaciji AND u bitovima.

info-600-117

 

Iz ovoga znamo da bez obzira da li je 1 ili 0, izvođenje operacije I sa 0 u bitovima rezultira 0.

Bilo da je 1 ili 0, izvođenje operacije I sa 1 u bitovima rezultira originalnom vrijednošću.

Radi praktičnosti, koristimo heksadecimalni zapis (sa prefiksom "0x"); na primjer, 0xff odgovara 255 u decimalnom obliku. stoga,

 

Kada je broj manji od ili jednak 0xff AND sa 0xff, rezultat je sam broj, kao što je prikazano ispod

info-534-63

 

 

Šta se događa ako izvedete operaciju I po bitu između broja većeg od 0xff i 0xff?

info-551-63

Rezultat je ostatak kada se ovaj broj podijeli sa (0xff + 1) (tj. rezultat je i dalje između 0 i 0xff).
Sa ovom operacijom I po bitovima, gornji kod se može pojednostaviti

info-550-64

 

 

Na ovaj način, vrijednost s_Counter će uvijek biti unutar raspona od 0x00 do 0xff.
Slično, softverski tajmer u gornjoj funkciji breath_led također se može pojednostaviti na sljedeći način:

info-389-353

U redu 3, 0x1ff je 511 u decimali. Uslov je tačan kada je vrijednost s_breathCounter (0x1ff+1), ili 512, jer 512 & 0x1ff=0. Znak uzvika prije nego označava operaciju NOT u bitovima (da budemo precizni, uvjet je ispunjen kada je vrijednost `s_breathCounter` višekratnik broja `s_breathCounter`; ovaj broj eliminiše potrebu za ponovnim postavljanjem 512. nadam se da je ovo objašnjenje jasno-promislite o tome). Ako je uslov ispunjen, radni ciklus počinje da se povećava ili smanjuje.


Ali nije li opseg radnog ciklusa od 0 do 255? Zašto red 5 također postaje 0x1ff (511)? Ne brinite-pogledajte red 8. Ponovo oduzimamo 0xff, tako da opseg radnog ciklusa ostaje od 0 do 255.


Linije 7–10 znače: Kada je `duty_cycle > (0xff)`, tj. 256–511, oduzimanje 0xff je ekvivalentno povećanju od 1 do 255, tako da se svjetlina postepeno povećava.


Kada 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, jesi li mislio da je naše pojednostavljenje gotovo?

 

Ne, ne, ne

Zapravo, redovi od 7 do 10 mogu se još više pojednostaviti. Ovdje je zgodna funkcija apsolutne vrijednosti.

sta? Zašto koristiti funkciju apsolutne vrijednosti?

 

Pogledajte red 10: 0xff - duty_cycle je ekvivalent duty_cycle - 0xff i onda uzima apsolutnu vrijednost. U redu, evo pojednostavljenog koda:

set_led_luminance(ABS(duty_cycle - (0xff)));

 

 

Makro funkcija za uzimanje apsolutne vrijednosti je sljedeća

#define ABS(N) ((N) < 0 ? -(N) : (N))

 

Konačno, u nastavku sam uključio cijeli pojednostavljeni kod

 

info-562-684

sta ti mislis Nije li jednostavno? (* ̄︶ ̄)

Pošaljite upit

whatsapp

Telefon

E-pošte

Upit