Przez kilka ostatnich odcinków eksperymentowaliśmy z „wirtualnymi kroplami deszczu” losowo padającymi na piksele w naszej matrycy i je rozświetlającymi. Pod koniec poprzedniego odcinka zauważyliśmy, że do tej pory pracowaliśmy tylko z jedną kroplą na raz. Przypuszczaliśmy również, że byłoby bardziej ekscytująco, gdybyśmy pozwolili na jednoczesną aktywność wielu kropelek, a czasy rozpoczęcia i zakończenia inicjowanych przez nie efektów świetlnych, byłyby losowo określane, tak aby nakładały się na siebie w interesujący i nieprzewidywalny sposób.
Oczywiście, jak większość rzeczy, implementacja takiego „rogu obfitości” do naszych obecnych kropelek brzmi łatwo, jeśli mówisz to szybko i wściekle gestykulujesz. Niestety, sposób, w jaki do tej pory implementowaliśmy rozwiązania w naszym kodzie, okaże się raczej ograniczający. Ale odwróćmy tę sytuację i uśmiechnijmy się, ponieważ nie pozwolimy, aby cokolwiek przeszkodziło nam w osiągnięciu naszej ekstrawagancji z wieloma kroplami, albo nie nazywam się Max the Magnificent.
W pewnym stanie
Rozważmy następującą interpretację funkcji main loop() używanej w klasycznym szkicu (programie) Arduino „Blink”. Załóżmy, że używamy tego programu do sterowania żółtą diodą LED. W tym konkretnym przykładzie włączamy i wyłączamy diodę LED z częstotliwością 1 Hz (jeden cykl na sekundę).
void loop()
{
digitalWrite(PinLed, LOW);
delay(500);
digitalWrite(PinLed, HIGH);
delay(500);
}
Termin „automat skończony” odnosi się do matematycznego modelu obliczeń. Podstawową ideą jest to, że mamy abstrakcyjny automat, który może znajdować się tylko w jednym ze skończonej liczby stanów w danym momencie. Powodem, dla którego o tym wspominam, jest to, że przedstawiony powyżej kod można uznać za implementację automatu skończonego, którego działanie można przedstawić graficznie.
Załóżmy teraz, że zdecydujemy się dodać czerwoną diodę LED, a obie diody LED będą włączać się i wyłączać z różną częstotliwością. Powiedzmy, że czerwona dioda LED ma częstotliwość 1 Hz, a żółta dioda LED ma częstotliwość 2 Hz. Główny kod pętli loop() mógłby wyglądać następująco (pełny szkic jest przedstawiony w pliku CB-Dec20-01.txt – on i inne pliki powiązane z tym artykułem są dostępne na stronie PE z grudnia 2020 r.).
void loop ()
{
// Stan 0
digitalWrite(PinRedLed, LOW);
digitalWrite(PinYellowLed, LOW);
delay(250);
// Stan 1
digitalWrite(PinRedLed, LOW);
digitalWrite(PinYellowLed, HIGH);
delay(250);
// Stan 2
digitalWrite(PinRedLed, HIGH);
digitalWrite(PinYellowLed, LOW);
delay(250);
// Stan 3
digitalWrite(PinRedLed, HIGH);
digitalWrite(PinYellowLed, HIGH);
delay(250);
}
W klasycznym automacie skończonym mielibyśmy jakiś sposób na zapamiętanie bieżącego stanu automatu. Może to być rejestr zawierający zmienne stanu w przypadku implementacji sprzętowej lub typ wyliczeniowy w przypadku implementacji programowej (więcej informacji na temat typów wyliczeniowych można znaleźć dalej w części „Sprytne porady i sztuczki”. Dla porównania, jeśli chodzi o nasz przykładowy kod pokazany powyżej, poza użyciem komentarzy, nie mamy żadnego sposobu na jawne zdefiniowanie bieżącego stanu. Zamiast tego stan jest implikowany przez miejsce, w którym znajdujemy się w kodzie.
Aby zilustrować, dlaczego jest to problem, załóżmy, że poproszę o dodanie zielonej diody LED o częstotliwości 3 Hz. Poświęć chwilę na zastanowienie się, jak zaimplementowałbyś kod do tego celu. Wyobrażam sobie, jak się uśmiechasz, bo choć wiesz, że wszystko jest ze sobą tak powiązane, że bez wątpienia utrudni to pracę, jesteś pewien, że – gdyby przyszło co do czego – mógłbyś to zrobić. Co powiesz na to, że zamiast po prostu włączać i wyłączać trzy diody LED, poproszę Cię, abyś je włączył, przytrzymał i wyłączył, przy czym każde wygaszenie zajmie 10 kroków w ciągu 100 milisekund (ms). Nie uśmiechasz się teraz, prawda?
Gdy się nad tym zastanowić, to właśnie w tym punkcie znajdujemy się z naszymi istniejącymi programami „kroplującymi”. Chociaż prawdą jest, że zaimplementowaliśmy kilka bardzo smacznych efektów wygaszania przy użyciu różnych kolorów, osiągnęliśmy to tylko przy jednej kropelce na raz. Będziemy musieli przyjąć nowe podejście, jeśli chcemy mieć wiele kropelek aktywnych jednocześnie w losowych relacjach między sobą.