micro:bit:led (full of stars!)

Jedną z ciekawszych części micro:bit jest 25-diodowe pole znajdujące się na górnej stronie płytki. Diody można zapalać, gasić – a nawet zmieniać jasność ich świecenia. Domyślna biblioteka pozwala na łatwe wyświetlanie strzałek, napisów, liczb, ikon itp.

Do ilustracji obsługi pola LED użyję środowiska JavaScript Blocks (https://makecode.microbit.org). Nowy program będzie powtarzał sekwencję:

  • Losuję jedno pole na wyświetlaczu (aka. „trafienie”),
  • Dla każdego pola będę zliczał ilość „trafień” zwiększając licznik o „1” przy każdym wylosowaniu pola,
  • Im więcej trafień – tym pole będzie świeciło jaśniej,
  • Wciśnięcie klawisza „A” pokaże na ekranie led maksymalną ilość trafień,
  • Klawisz „B” wyzeruje licznik trafień.

Efekt powinien być ciekawy, przy okazji nauczymy się kilku nowych trików z ledami – no i przetestujemy generator liczb losowych:) Do roboty.

Kod

setup() i loop(): te dwie funkcje pojawiają, gdy otworzycie pusty projekt w Arduino IDE. setup() wywoływany jest raz po resecie, a loop() – w kółko przez cały czas działania programu. Odpowiednikami setup() i loop() w świecie micro:bit są on start()” i „forever().

on start

Bloczek „on start” to odpowiednik arduinowej funkcji „setup()”. Jest wywoływany raz, przy starcie programu (np. po resecie micro:bit). Najlepiej wykorzystać go do inicjalizacji zmiennych.

U mnie:

  • Zmienna stopForever – taka trochę „maszyna stanów”, którą później użyję do sterowania wyświetlaniem w funkcji forever(),
  • Lista ledArray – 25 elementów, w której zapisuję kolejne „trafienia” pól wyświetlacza; elementy listy odpowiadają 25 ledom na wyświetlaczu.

Przeciągnięcie 25 bloczków „0” (z Math) może być trochę… nużące:) Może łatwiej przełączyć się na „JavaScript” i „ręcznie” dopisać w odpowiednim miejscu:

Dodatkowa funkcja

Jasność diod ma odpowiadać ilości ich „trafień” (ile razy wylosowano diodę na pozycji x,y). Żeby odpowiednio wyskalować wyświetlanie, muszę znać  maksymalną ilość trafień diody. To będzie moje 100%, najjaśniejsza dioda. Jasność pozostałych diod wyskaluję w stosunku do tej, która otrzymała najwięcej trafień.

Do znalezienia pola z największą liczbą trafień stworzyłem funkcję getMaxOccurrences(). Funkcja ta sprawdza wszystkie elementy listy ledArray. Najwyższą znalezioną ilość „trafień” przypisuje zmiennej globalnej maxOccurrences.

Własne funkcje możecie tworzyć z grupy Advanced/Functions/Make a Function:

Zmienna globalna? Tak… w odróżnieniu do zmiennej lokalnej. Chodzi o zakres, w jakim widoczne są zmienne. Umówmy się, że zmienne globalne widoczne są w całym programie; lokalne jedynie w jakimś jego fragmencie – np. tylko funkcji czy bloku kodu.

Zdarzenia

Dodałem obsługę zdarzeń wciśnięcia klawiszy A i B:

Wciśnięcie klawisza „A” wyświetla strzałkę w górę (kierunek: North) a potem liczbę: największą ilość trafień (zmienna maxOccurences). Wciśnięcie klawisza B czyści listę z wynikami.

Główna pętla

forever jest odpowiednikiem Arduinowej funkcji loop(). Po opuszczeniu, forever wywoływana jest powtórnie – i tak w kółko aż do resetu.

Główna pętla wymaga trochę dłuższego wyjaśnienia:

  • Jeżeli stopForever jest „fałszem” (o tym później):
    • Pod x i y podstaw liczby losowe z przedziału 0..4,
    • Oblicz przesunięcie (x, y)w ledArray (index),
    • Zwiększ o „1” wartość w tablicy ledArray na pozycji index,
    • wywołaj funkcję getMaxOcurrences(), która ustawi zmienną globalną maxOccurences.
    • teraz zapalaj diody zgodnie z ilością „trafień” obliczaną jaką procent maksymalnej ilości trafień, dla
      • 99% i więcej: maksymalna jasność,
      • 80% do 99% – jasność 10,
      • Inaczej – wyłącz led

Cały kod poniżej:

Czas na kilka szczegółów:)

Skoro już napisaliście i uruchomiliście przykład  – czas na kilka tricków, które się za nim kryją.

Kilka przydatnych funkcji:

Szczegóły działania funkcji związanych z polem LED znajdziecie w materiałach dostarczonych razem ze środowiskiem. Wystarczy wybrać „?” i „Reference”.

Tutaj wymienię jedynie kilka z nich:

Metoda Grupa Opis
enable Led Włącza/wyłącza pole LED (zobacz niżej)
plot Led Zapala diodę na zadanej pozycji (x, y)
unplot Led Gasi diodę
toggle Led Jeżeli dioda była zapalona gasi ję, jeżeli zgaszona – zapala
point Led Sprawdza, czy dioda na pozycji (x,y) jest zapalona.
clearScreen Basic Czyści „ekran” diod – gasi je wszystkie.
showNumber Basic Wyświetla cyfrę na ekranie
showLeds Basic Ustawia pole LED – kliknijcie w diodę, żeby ją zapalić:

showIcon Basic
showArrow Basic Pokazuje na ekranie strzałkę o wybranym kierunku”
plotBarGraph Led Buduje pionowy pasek z LED
setBrightness Led Ustawia jasność diod, w zakresie 0-255 (o tym niżej)
brigthness() Led Zwraca aktualnie ustawioną jasność diod
stopAnimation Led Zatrzymuje trwające animacje (o tym poniżej)
Adresowanie

Pole diodowe ma rozmiar 5×5 – 5 kolumn na 5 rzędów. Adres każdej diody to: (kolumna, rząd), gdzie kolumna i rząd mogą przyjmować wartości 0, 1, 2, 3, 4. Przykładowo, dioda (0,0) to lewy górny róg, a (4,4) to prawy dolny.

Matematyka przyzwyczaiła nas, że „y” maleją w dół – a nie rosną jak tutaj.

Jasność

Diody mogą być zapalone, zgaszone – możecie również ustawiać im jasność. Służy do tego element plot-x-y-brightness:

Jasność może zawierać się w granicach 0 – 255. Wskazujecie diodę na pozycji (x, y) oraz jej jasność.

Sprawdzajcie jasność diod na urządzeniu!

Sprawdzajcie jasność diod na urządzeniu! Symulator na stronie środowiska traktuje poziomy jasności liniowo, np. 127 „wygląda” jak połowa jasności. Ale pamiętajcie, że LED’y świecą – a nie odbijają światło. W rezultacie między 127 a 255 – trudno jest zobaczyć różnicę:)

plotBrightness(): uwaga!

W powyższym kodzie użyłem funkcji plotBrightness(). W zależności od ostatniego parametru pozwala ona na „przyciemnienie” lub „rozjaśnienie” pikseli – w zakresie 0..255 (255 to wartość domyślna – pełna jasność).

Spójrzcie jednak na poniższy przykład:

Okazuje się, że pomimo wywołania „set Brightness (255)”, który powinien przywrócić maksymalną jasność – znaczek pojawiający się na ekranie pozostanie „przydymiony”.

Jedyne rozwiązanie tego problemu, jakie na razie znalazłem to:

  • Przełączcie się w tryb „JavaScript” i w funkcji wyświetlającej znaczek (showLeds, show Arrow) dopiszcie linijkę:

  • Komenda „setDisplayMode” nie jest znana środowisku, więc w widoku bloczkowym – system doda szary element z kodem:

Teraz już znaczek wyświetli się w pełnej jasności.

W moim przykładzie komenda ta pojawiła się w bloku obsługi wciśnięcia klawisza:

Kolejność ma znaczenie

Musicie być świadomi, że funkcje wyświetlające ikony, strzałki itp. nadpisują całe pole. Poniższe nie są równoważne:

W górnym kodzie na ekranie pojawi się jedynie strzałka, a nie punkt (0,0).

stopAnimation – przydatne!

Spójrzcie na poniższy fragment kodu:

  • W pętli „forever” wyświetlane są gwiazdki,
  • Po wciśnięciu klawisza „A” na ekranie powinien się pojawić napis „Break”

Efekt? Na ekranie przewijają się gwiazdki. Po wciśnięciu klawisza „A”… nic się nie dzieje? O zaraz, napis pojawia się… Ale czemu z takim opóźnieniem?

Rozkaz wyświetlenia napisu „Break” (umieszczony w procedurze obsługi zdarzenia wciśnięcia klawisza „A”) będzie musiał poczekać, aż w pętli głównej „forever” skończy się wyświetlanie gwiazdek. Można to zmienić:

Teraz „break” wyświetli się, gdy tylko użytkownik wciśnie „A”. Tak działa instrukcja „stop animation”.

„Wcinanie” obsługi zdarzeń do głównej pętli

Kolejnym problemem w programowaniu obsługi wyświetlacza jest zmiana jego zawartości z wnętrza funkcji obsługujących zdarzenia np. po wciśnięciu klawiszy (tzw. event handlers). Podobnie jak w moim przykładzie:

  • W głównej pętli forever odświeżany jest stan pola LED,
  • W procedurze obsługi chcę wyświetlić najwyższą ilość „trafień”.

„Stop animation” tu nie zadziała. Generalnie strategie są dwie:

  • blokuję wyświetlanie w forever i wyświetlam napis w funkcji obsługi
  • ustawiam flagę w funkcji obsługi, na którą reakcja znajduje się w forever.

Generalnie drugie rozwiązania jest lepsze. Wasze funkcje obsługi zdarzeń powinny być jak najkrótsze. Tutaj postąpiłem jednak inaczej.

Jak widzicie, w po wciśnięciu klawisza ustawiam stopForever na wartość 1. Zmienna jest sprawdzana w pętli głównej forever – i tylko jeżeli jest równa „0” – pętla kontynuuje losowanie liczby i odświeżanie pola led. Gdy już skończę wyświetlanie w funkcji obsługi zdarzenia wciśnięcia klawisza – „odblokowuję” wyświetlanie przypisując „0” zmiennej stopForever.

Wyłączanie LED

Oczywiście wszystko ma swoją cenę. Używanie pola LED oznacza nie tylko większy pobór mocy. Obsługa pola LED wymaga zaangażowania kilku pinów, które w innych warunkach – moglibyście wykorzystać do innych celów.

LED obsługiwane są przez następujące porty:

  • pin 3: sterowanie LED; inaczej przetwornik analog-cyfra lub port cyfrowy,
  • pin 4: sterowanie LED; inaczej przetwornik analog-cyfra lub port cyfrowy,
  • pin 6: sterowanie LED; inaczej port cyfrowy,
  • pin 7: sterowanie LED; inaczej port cyfrowy,
  • pin 9: sterowanie LED; inaczej port cyfrowy,
  • pin 10: sterowanie LED; inaczej przetwornik analog-cyfra lub port cyfrowy.

Innymi słowy użycie pola LED blokuje 6 portów we/wy (włączając w to 3 porty przetwornika analog-cyfra). Jeżeli użyjecie komendy:

Podsumowanie

Oczywiście nie będzie większym zaskoczeniem, że po pewnym czasie…:

Chociaż… wiecie jak to jest ze statystyką… może ale nie musi:)

Źródła

  • https://www.microbit.co.uk/device/screen
  • http://tech.microbit.org/hardware/schematic/
  • https://meanderingpi.wordpress.com/2017/08/05/microbit-analog-inputs/

Dodaj komentarz

Proszę dodaj swój komentarz. Pamiętaj, żeby nie podawać żadnych danych osobowych.