7.4 RGB LED kontroler
Ovaj projekt tjera RGB LED-icu da mijenja boju sa svjetlom u prostoriji. U tami svijetli crveno; kako svjetlo raste, boja klizi kroz zelenu i plavu, a na stvarno jakom svjetlu postaje bijela.
Spaja dvije stvari koje si već sagradio. Krug s fotootpornikom točno je onaj iz 2.3 Analogno čitanje fotootpornika, a ideja postavljanja svjetline umjesto samo uključivanja i isključivanja pina dolazi iz 3.2 Udaljenost i zatamnjivanje LED-ice. Novo je to što jedna vrijednost senzora sada pobuđuje tri izlaza u isto vrijeme.
U ovoj dokumentaciji naučit ćeš:
- Kako naći četiri nožice RGB LED-ice i koja je dijeljena.
- Kako se jedna analogna vrijednost može pretvoriti u tri odvojene svjetline.
- Kako PWM miješa crvenu, zelenu i plavu u bilo koju boju između.
- Kako pretvoriti poznate brojeve boja 0–255 u ono što
duty_u16()želi. - Zašto boja glatko prelazi umjesto da skače.
Potreban hardver:
- 1x Soldered NULA MINI pločica
- 1x Breadboard
- 1x Fotootpornik (LDR)
- 1x RGB LED-ica
- 1x otpornik od 10 kΩ
- 3x otpornika od 330 Ω
- 8x Jumper žice
- 1x USB-C kabel
Spajanje komponenti
Prati dvanaest koraka ispod. Svaka fotografija snimljena je s istog položaja, pa je možeš usporediti s prethodnom i vidjeti točno što se promijenilo.
1. Umetni NULA MINI pločicu na breadboard
Utisni pločicu u jedan kraj breadboarda tako da njezina dva reda pinova sjednu s obje strane središnjeg kanala, s čipom okrenutim prema dolje. Trebala bi zauzeti redove 25 do 30.

2. Izvedi masu na vodilicu
Jedna jumper žica iz j30 (GND) do plave − vodilice. Ta vodilica postaje dijeljena masa cijelog kruga, i obje se polovice vraćaju na nju.

3. Izvedi 3.3 V u red 14
Druga jumper žica, iz j29 (3V3) gore u red 14. To je vrh mjernog kruga.

4. Dodaj fotootpornik
Fotootpornik premošćuje red 14, u koji sada dolazi 3.3 V, i red 11.

5. Dodaj otpornik od 10 kΩ
Otpornik nastavlja lanac prema dolje, iz reda 11 u red 9.

6. Spoji otpornik na masu
Jedna jumper žica iz reda 9 do plave − vodilice.

Lanac je sada potpun: 3.3 V → fotootpornik → 10 kΩ → GND. Struja teče kroz oba dijela serijski.
7. Zahvati sredinu pomoću IO5
Sada samo mjerenje. Povuci jumper žicu iz j28 (IO5) u red 11, red koji dijele donja nožica fotootpornika i gornji izvod otpornika.

IO5 mjeri. Ako žica sleti u red 14 ili red 9, i dalje ćeš dobivati vrijednost. Samo se neće mijenjati kada se svjetlo mijenja.8. Dodaj RGB LED-icu
RGB LED-ica je tri LED-ice u jednom pakiranju koje dijele jednu nožicu. Drži je s nožicama okrenutima prema dolje i nađi najdulju. To je dijeljena nožica, zajednička katoda. Na ovoj LED-ici ona je treća po redu, s jednom nožicom s jedne strane i dvjema s druge.
Postavi LED-icu tako da njezine četiri nožice slete u redove 1, 2, 3 i 4, s dugom nožicom u redu 3:
| Nožica | Red |
|---|---|
| Crvena, krajnja, najdalja od duge nožice | 1 |
| Zelena, između crvene i duge nožice | 2 |
| Zajednička katoda, najdulja nožica | 3 |
| Plava, sama s druge strane duge nožice | 4 |

9. Spoji zajedničku katodu na masu
Jedna jumper žica iz reda 3 do plave − vodilice. Sva tri kanala boje vraćaju se na masu preko te jedne žice.

10. Dodaj tri otpornika od 330 Ω
Svakom kanalu boje treba vlastiti ograničivač struje. Premosti svaku od tri nožice boje do slobodnog reda dalje duž pločice:
- iz reda 1 (crvena) u slobodan red
- iz reda 2 (zelena) u drugi slobodan red
- iz reda 4 (plava) u treći slobodan red

11. Spoji tri kanala boje na pločicu
Još tri jumper žice, s dalekog kraja svakog otpornika natrag na odgovarajući pin. Koristi tri različite boje žica, jer idu jedna uz drugu i kasnije ćeš ih htjeti razlikovati.
| Kanal | Iz | U |
|---|---|---|
| Crvena | slobodan red crvenog otpornika | j25 (IO2) |
| Zelena | slobodan red zelenog otpornika | j26 (IO3) |
| Plava | slobodan red plavog otpornika | j27 (IO4) |

GND, 3V3, IO5, IO4, IO3, IO2), a ne nagađaj iz sredine.12. Spoji pločicu na računalo

Kako jedan senzor postaje tri boje
Čitanje svjetla
Pločica ne može mjeriti otpor, samo napon. Fotootpornik mijenja svoj otpor sa svjetlom, pa sam za sebe pločici ne daje ništa za čitanje. Spajanje s fiksnim otpornikom od 10 kΩ pravi djelitelj napona, a napon u točki između njih ovisi o odnosu njihovih otpora:
- Na jakom svjetlu otpor fotootpornika pada, zadržava manje od 3.3 V za sebe, i vrijednost na
IO5raste. - U tami njegov otpor raste, zadržava veći dio napona, i vrijednost pada.
ldr.read() taj napon pretvara u broj od 0 do 4095, jer NULA MINI ima 12-bitni ADC.
Postavljanje boje
Svaki kanal je PWM objekt, stvoren s brzinom prebacivanja zadanom unaprijed:
pwm_r = PWM(Pin(RED_PIN), freq=PWM_FREQ)
pwm_g = PWM(Pin(GREEN_PIN), freq=PWM_FREQ)
pwm_b = PWM(Pin(BLUE_PIN), freq=PWM_FREQ)
Umjesto da pin samo uključi potpuno ili isključi potpuno, PWM ga uključuje i isključuje vrlo brzo, ovdje 1000 puta u sekundi, i što pin dulje ostaje uključen unutar svakog ciklusa, to taj kanal izgleda svjetlije. Pisanje svih triju odjednom je ono što miješa boju.
Problem 0–255, i funkcija koja ga rješava
Svi o boji razmišljaju u rasponu 0 do 255: 255, 0, 0 je crvena, 0, 255, 0 je zelena, 255, 255, 255 je bijela. To je ono što koristi svaki program za slikanje i svaka web stranica.
Ali duty_u16() želi broj od 0 do 65535. Umjesto da tu pretvorbu razaspe po kodu za boje, skripta je radi jednom u vlastitoj funkciji:
def write_colour(pwm, brightness):
pwm.duty_u16(int(brightness * 65535 / 255))
analogWrite(RED_PIN, r) i izvorno radi u 0–255, pa joj pretvorba ne treba uopće. MicroPython radi u 0–65535, a write_colour() tu činjenicu drži na jednom mjestu tako da logika boja ispod može ostati u poznatom rasponu.int() ponovno radi nužan posao. brightness * 65535 / 255 u Pythonu proizvodi decimalni broj, a duty_u16() ga odbija. Bez int() skripta pada s TypeError.Spajanje svega
Raspon svjetla razdijeljen je na tri jednaka dijela. FIRST_THIRD je 1365 a SECOND_THIRD je 2730, jednostavno 4095 podijeljen na trećine, a svaki dio dobiva svoj prijelaz:
LDR vrijednost | Što kod radi | Rezultat |
|---|---|---|
| 0 → 1365 | crvena slabi dok zelena jača | crvena → zelena |
| 1366 → 2730 | zelena slabi dok plava jača | zelena → plava |
| 2731 → 4095 | plava ostaje puna dok crvena i zelena rastu | plava → bijela |
U svakom dijelu jedan kanal preslikava se prema gore dok se drugi preslikava prema dolje. To je ono što jednu boju tjera da klizne u sljedeću umjesto da skoči. A budući da svaki dio počinje točno tamo gdje je prethodni završio, granice su nevidljive: na 1365 boja je čista zelena s koje god strane joj pristupiš.
Samo preskaliranje koristi istu funkciju value_map() koju si napisao u 3.2, jer MicroPython i dalje nema ugrađen map().
Kod
# ADC mjeri stvarni napon na pinu i daje nam broj za njega, a tako čitamo razinu svjetla. PWM
# uključuje i isključuje pin vrlo brzo, a tako postavljamo svjetlinu umjesto samo uključeno ili isključeno.
from machine import Pin, ADC, PWM
import time
# Ovo je varijabla kojoj predajemo broj pina na koji smo spojili izlaz fotootpornika.
# Budući da ovdje moramo pročitati cijeli raspon vrijednosti a ne samo visoko ili nisko, to mora biti pin koji podržava
# analogni ulaz.
#
# Ovom primjeru također treba otpornik od 10k. Fotootpornik mijenja svoj otpor sa svjetlom, ali pločica može
# mjeriti samo napon, pa ta dva spajamo u ono što se naziva djelitelj napona.
LDR_PIN = 5
# Ovo su varijable kojima predajemo brojeve pinova na koje smo spojili tri kanala boje
# RGB LED-ice. RGB LED-ica je u stvari tri LED-ice u jednom pakiranju, jedna crvena, jedna zelena i jedna plava, a paljenjem
# na različitim jačinama možemo pomiješati bilo koju boju koju želimo.
#
# Zapamti da svakom od tri kanala boje treba vlastiti otpornik od 330 ohma u seriji s njim. RGB LED-ica se računa
# kao tri LED-ice, pa traži tri otpornika.
RED_PIN = 2
GREEN_PIN = 3
BLUE_PIN = 4
# Ovoliko brzo PWM pinovi prebacuju uključeno i isključeno. 1000 puta u sekundi je daleko brže nego što naše oči mogu pratiti, pa
# vidimo postojane boje umjesto treperenja.
PWM_FREQ = 1000
# Ove dvije varijable razdjeljuju raspon svjetla na tri jednaka dijela, a to je ono što nam daje naša tri prijelaza
# boje. Vrijednosti fotootpornika idu od 0 do 4095, a 4095 podijeljeno s tri je 1365.
FIRST_THIRD = 1365
SECOND_THIRD = 2730
# Ovdje stvaramo naš ADC objekt, koji smo nazvali "ldr". Postavka atten odabire koliko velik napon pretvarač
# može mjeriti, a ADC.ATTN_11DB je najšira postavka, koja nam dopušta korištenje cijelog raspona fotootpornika.
ldr = ADC(Pin(LDR_PIN), atten=ADC.ATTN_11DB)
# Ovdje stvaramo po jedan PWM objekt za svaki kanal boje, sve na istoj brzini prebacivanja.
pwm_r = PWM(Pin(RED_PIN), freq=PWM_FREQ)
pwm_g = PWM(Pin(GREEN_PIN), freq=PWM_FREQ)
pwm_b = PWM(Pin(BLUE_PIN), freq=PWM_FREQ)
def value_map(value, in_min, in_max, out_min, out_max):
# Ovo je funkcija koju smo napisali sami, jer ne postoji gotova funkcija za preskaliranje broja.
# Uzima broj iz jednog raspona i preskalira ga u drugi raspon, a tako razinu svjetla pretvaramo u
# svjetlinu.
return int((value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
def write_colour(pwm, brightness):
# Ova funkcija šalje jedan kanal boje na njegov pin.
# O bojama razmišljamo kao o brojevima od 0 do 255, kako to radi gotovo svaki program, ali duty_u16() želi
# broj od 0 do 65535. Ova funkcija tu pretvorbu radi na jednom mjestu, pa kod za boje ispod ostaje lako
# čitljiv.
pwm.duty_u16(int(brightness * 65535 / 255))
# Ispiši početnu poruku da znamo da se program uspješno pokrenuo.
print("RGB LED Controller with full-spectrum color mapping started")
while True:
# read() čita napon na analognom pinu i pretvara ga u broj. Budući da NULA pločica koristi 12-bitni
# ADC, vrijednost ide od 0 u potpunoj tami do 4095 na jakom svjetlu. Što više svjetla pada na
# fotootpornik, to je njegov otpor manji a ovaj broj veći.
ldr_value = ldr.read()
print("LDR value:", ldr_value)
# Ovdje se boja odlučuje. Raspon svjetla razdjeljujemo na tri dijela i svakom dajemo vlastiti
# prijelaz, tako da boja nikada ne skoči: uvijek klizne odakle je bila u sljedeću boju.
# Primijeti kako se u svakom dijelu jedan kanal preslikava prema gore dok se drugi preslikava prema dolje.
if ldr_value <= FIRST_THIRD:
# Najtamnija trećina: prijelaz od crvene (255, 0, 0) do zelene (0, 255, 0).
r = value_map(ldr_value, 0, FIRST_THIRD, 255, 0)
g = value_map(ldr_value, 0, FIRST_THIRD, 0, 255)
b = 0
elif ldr_value <= SECOND_THIRD:
# Srednja trećina: prijelaz od zelene (0, 255, 0) do plave (0, 0, 255).
r = 0
g = value_map(ldr_value, FIRST_THIRD + 1, SECOND_THIRD, 255, 0)
b = value_map(ldr_value, FIRST_THIRD + 1, SECOND_THIRD, 0, 255)
else:
# Najsvjetlija trećina: prijelaz od plave (0, 0, 255) do bijele (255, 255, 255). Bijela je jednostavno sva tri kanala uključena
# odjednom, i zato crvena i zelena ovdje rastu dok plava ostaje na punoj svjetlini.
r = value_map(ldr_value, SECOND_THIRD + 1, 4095, 0, 255)
g = value_map(ldr_value, SECOND_THIRD + 1, 4095, 0, 255)
b = 255
# Ovdje pišemo sva tri kanala odjednom, a to je ono što miješa boju.
write_colour(pwm_r, r)
write_colour(pwm_g, g)
write_colour(pwm_b, b)
# Ispiši i pomiješanu boju, da je možemo usporediti s razinom svjetla iznad.
print("RGB:", r, g, b)
# Kratka pauza između vrijednosti. Držanje male čini promjene boje glatkima.
time.sleep_ms(100)
Što bi trebao vidjeti
Pritisni Run. Pojavljuje se početna poruka, a zatim dvije linije dolaze deset puta u sekundi: sirova vrijednost svjetla i tri svjetline koje je kod iz nje izračunao.
U običnoj osvijetljenoj prostoriji vrijednost sjedi nešto ispod trećine puta gore po rasponu, u prvom pojasu, pa se LED-ica smjesti na zelenu s nešto crvene u sebi.

RGB LED Controller with full-spectrum color mapping started
LDR value: 1057
RGB: 57 197 0
LDR value: 1058
RGB: 57 197 0
Sada stavi ruku preko fotootpornika. Vrijednost pada negdje oko stotinu, što je gotovo dno prvog pojasa, i boja prelazi na crvenu.
LDR value: 106
RGB: 235 19 0
Odmakni ruku i umjesto toga prisloni svjetlo mobitela na senzor. Vrijednost se uzdiže u srednji pojas i boja ide na plavu.

LDR value: 2465
RGB: 0 49 205
Te vrijednosti vrijedi usporediti, jer računanje koda možeš provjeriti napamet. Na 1057 vrijednost je u prvom pojasu, pa se crvena preslikava dolje od 255 a zelena gore od 0: 255 − 1057 × 255 ÷ 1365 je 57.5, a int() odbacuje decimalni dio i daje 57 koji je ispisan. Broj na ekranu i boja pred tobom su ista činjenica, dvaput.
int() uvijek reže prema nuli, nikada ne zaokružuje. 57.5 postaje 57, a ne 58. To vrijedi znati ako te brojeve usporediš s Arduino verzijom istog projekta, koja ovdje ispisuje 58: Arduinov map() cijelo računanje radi u cijelim brojevima i decimalni dio odbacuje na drugom mjestu, pa se dvije platforme mogu razlikovati za jedan na svakom kanalu koji se preslikava prema dolje. Jedna jedinica od 255 daleko je previše mala da bi se vidjela.Cijeli raspon
| Što radiš | Približno što ćeš pročitati | RGB | Boja |
|---|---|---|---|
| Čvrsto ga prekrij dlanom | ~90–150 | 232, 22, 0 | crvena |
| Zasjeni ga rukom, opušteno | ~260–430 | 190, 64, 0 | narančasto-crvena |
| Ostavi ga u osvijetljenoj prostoriji | ~1000–1070 | 61, 193, 0 | zelena |
| Osvijetli ga svjetlom mobitela | ~2300–2530 | 0, 58, 196 | plava |
IO5 stvarno zahvaća red 11.Ako boje izađu pogrešno
Ako se LED-ica pali ali prikazuje pogrešnu boju (zelenu gdje očekuješ crvenu, ili jedan kanal koji se nikada ne upali), krug je u redu a preslikavanje nije. Prođi kroz to u ovom redoslijedu:
- Provjeri je li duga nožica u redu 3 i spojena na − vodilicu. Ako je dijeljena nožica negdje drugdje, kanali se međusobno bore i većinom ostaju tamni.
- Provjeri obuhvaća li svaki otpornik dva reda. Kratko spojen otpornik čini svoj kanal daleko svjetlijim od druga dva, što se čita kao da ta boja preuzima.
- Zamijeni jumper žice na strani pločice. Ako su crvena i plava zamijenjene, zamijeni žice u
j25ij27. Konzola ti kaže koju je boju pločica namjeravala: ako ispisujeRGB: 255 0 0a ti vidiš plavu, dva kanala su prekrižena. - Blijeda, isprana boja koja se jedva miče upućuje na postavku
atten, a ne na LED-icu. SADC.ATTN_0DBna mjestuADC.ATTN_11DBisto svjetlo u prostoriji čita blizu 3900 umjesto oko 1050, što kod parkira u njegovom najvišem pojasu i ostavlja LED-icu blizu bijele što god radiš.
Ta posljednja je korisna navika: linija RGB je vlastita izjava pločice o tome što pokušava prikazati, pa je svako neslaganje između nje i LED-ice pred tobom greška u spajanju, a ne greška u kodu.
Cijeli primjer
Pogledaj cijeli kod primjera na linku ispod:
7.4_RGB_LED_Controller.py
Projekt koji pomoću fotootpornika upravlja RGB LED-icom, glatko mijenjajući boju od crvene do bijele na temelju jačine okolnog svjetla.