ISIX-RTOS – trzy wątki, przykłady w języku C: termometr z wyświetlaczem LED-RGB

Pierwsza seria artykułów zawierająca wprowadzenie do systemu ISIX z przykładami w języku C++ cieszyła się dużym zainteresowaniem wśród użytkowników portalu www.stm32.eu. Napływające pytania skłoniły mnie do napisania drugiej wersji przykładów – tym razem napisanych w języku C.

Opis systemu ISIX-RTOS i jego funkcji opublikowaliśmy w artykule “Mini system operacyjny dla STM32 – wprowadzenie”, który można przeczytać tu.

Pierwsza seria artykułów zawierająca wprowadzenie do systemu ISIX z przykładami w języku C++ cieszyła się dużym zainteresowaniem wśród użytkowników portalu www.stm32.eu. Napływające pytania skłoniły mnie do napisania drugiej wersji przykładów – tym razem napisanych w języku C. W przykładzie opisanym poniżej pokażemy, jak tworzyć wątki w języku C z wykorzystaniem systemu ISIX oraz w jaki sposób skomunikować je ze sobą. Przedstawimy również możliwość wykorzystania wątków do realizacji trzech niezależnych zadań. W naszym przykładzie jeden wątek odpowiada za obsługę diody LED-RGB zainstalowanej na module KAmodRGB, drugi wątek za odczyt wyniku pomiaru temperatury za pomocą układu MCP9801 (KAmodTEM), trzeci natomiast odpowiada za obsługę diody LED zamontowanej na płytce STM32Butterfly. 

Prezentowane urządzenie jest nietypowym termometrem, wskazującym temperaturę nie w wartościach liczbowych lecz za pomocą koloru świecenia LED-RGB. Prezentacja odbywa się na zasadzie pokazania na diodzie LED-RGB temperatury na zasadzie ciepło-zimno, gdzie kolor niebieski oznacza „zimno”, natomiast kolor czerwony „ciepło”. Wszystkie pośrednie temperatury prezentowane są przez kolory pośrednie. Jest to najbardziej naturalny sposób interpretacji, gdyż za pomocą tylko jednego spojrzenia możemy zorientować jaka jest aktualna temperatura.
Sterowanie diod LED RGB może być zrealizowane bezpośrednio za pomocą generatorów PWM wbudowanych w mikrokontroler lub za pomocą specjalizowanych układów dedykowanych do tego celu. W przykładzie zastosowano moduł KAmodRGB, który wyposażono w wyspecjalizowany 4-kanałowy sterownik PCA9633 firmy NXP, komunikujący się z otoczeniem za pomocą magistrali I2C. Dzięki zastosowaniu tego sterownika mikrokontroler przesyła dane o jasności LED w każdym kanale R-G-B za pomocą magistrali I2C, a generacją odpowiednich sygnałów zajmuje się PCA9633. Schemat połączeń pomiędzy modułami pokazano na rys. 1.

 

 

Rys. 1. Schemat połączeń elektrycznych pomiędzy STM32Butterfly i modułami KAmodRGB oraz KAmodTEM

Po połączeniu obu modułów z zestawem STM32Butterfly należy w module KAmodRGB przestawić wszystkie zwory konfiguracji adresu w pozycje „0” (rys. 1), w efekcie czego będzie on dostępny na magistrali pod adresem 0x00, natomiast czujnik w module KAmodTEM (zwory na liniach adresowych nie są zakładane  pod adresem 0x90 (rys. 1).

 

 

Rys. 2. Podział zadań na wątki w prezentowanym przykładzie

Sposób działania przykładowej aplikacji z uwzględnieniem podziału na wątki przedstawiono na rys. 2. Zasada działania aplikacji jest w zasadzie identyczna jak w przykładzie, różnica polega jedynie na zmianie funkcji wątku wyświetlania. Program rozpoczyna działanie od funkcji main() (list. 1).

List. 1. Funkcja main

 

Najpierw tworzony jest niezależny wątek migania diodą D1 (zamontowana na pytce „motyla”), następnie tworzona jest kolejka FIFO, której maksymalną pojemność ustawiono na 10 elementów zdefiniowanych jako struktura msg. Następnie inicjalizowana jest biblioteka obsługi magistrali I2C, a następnie w przypadku pomyślnego utworzenia kolejki FIFO, tworzone jest zadanie odczytu temperatury temp_read_task oraz wątek wyświetlania temperatury display_srv_task. Po utworzeniu wszystkich wątków, uruchamiany jest planista zadań systemu ISIX. Strukturę wiadomości nieco odmienną niż w poprzednim przypadku zdefiniowano w sposób pokazany na list. 2.

List. 2. Struktura wiadomości przekazywanej pomiędzy wątkami

 

W tym przypadku celowo, aby pokazać że operacje zmienno-przecinkowe wykonywane są przez rdzeń Cortex-M3 bardzo sprawnie, zdecydowano się na zdefiniowanie temperatury w postaci liczby zmiennoprzecinkowej typu float. Ten typ zostanie również użyty w przypadku obliczenia nasycenia barw w zależności od temperatury, o czym napiszemy w dalszej części.
Za odczytywanie temperatury z czujnika MCP9801 odpowiada wątek temp_read task, który działa identycznie jak w poprzednim przykładzie, jedyna różnica występuje w funkcji tempsensor_get() (list. 3), w której wartość temperatury jest przeliczana na liczbę zmiennoprzecinkową.

List. 3. Funkcja tempsensor_get()

 

Tak wyliczona wartość jest przekazywana do struktury msg i przesyłana do kolejki FIFO. Za wizualizację temperatury odpowiedzialny jest wątek display_srv_task, który odbiera informację o aktualnej temperaturze z kolejki FIFO i wizualizuje ją na diodzie RGB (list. 4).

List. 4. Wątek odpowiadający za odbiór danych o aktualnej temperaturze z kolejki FIFO i jej wizualizację na diodzie RGB

 

Wątek wizualizacji rozpoczyna działanie od inicjalizacji modułu KAmodRGB poprzez wywołanie funkcji rgb_init() (list. 5). W przypadku niepowodzenia (rezultat <0) funkcja isix_task_delete(NULL) kasuje bieżący wątek który ją wywołał. Jeżeli inicjalizacja przebiegła poprawnie zadanie przechodzi do pętli realizującej cykl sterowania modułem KAmodRGB.

List. 5. Wątek inicjalizacji modułu KAmodRGB

 

Inicjalizacja modułu KAmodRGB sprowadza się do przesłania parametrów konfiguracyjnych do rejestrów układu PCA9633. Do rejestru konfiguracyjnego MODE1 (0x00) przesyłana jest wartość 0, co oznacza że układ PCA będzie reagował tylko na adres własny (istnieje również możliwość reakcji na adres grupowy, co umożliwia równoczesne sterowanie kilku układów na magistrali). Do rejestru konfiguracyjnego MODE2 (0x01) wpisywana jest również wartość 0, co powoduje skonfigurowanie wszystkich wyjść sterujących pracą LED jako open-drain. Na koniec inicjalizacji do rejestru LEDOUT (0x08) jest wpisywana wartość 255, co powoduje uruchomienie wszystkich 4 kanałów PWM.
Jeżeli inicjalizacja przebiegła pomyślnie, wówczas program wchodzi do pętli głównej, w której cyklicznie odczytywane są wiadomości otrzymywane od wątku odczytującego temperaturę z czujnika. Jeżeli w strukturze wiadomości nie został ustawiony kod błędu, wówczas wyznaczany jest poziom nasycenia poszczególnych barw RGB na podstawie aktualnej temperatury. Wartości skrajne temperatury COLD_VALUE (kolor niebieski) i HOT_VALUE (kolor czerwony) zdefiniowano odpowiednio na wartości 24 i 30oC, dzięki czemu jedynie poprzez dotknięcie ręką czujnika, temperatury będziemy mogli zobaczyć zmieniające się barwy od niebieskiego do czerwonego. Ponieważ układ PCA9633 ma 8-bitowe PWM-y, wartość 0 odpowiada odpowiednio wygaszeniu diody dla danego kanału, a 255 pełną jasność diody. Wyznaczenie współczynnika PWM dla nasycenia kolorów R i B została zrealizowana jako prosta funkcja liniowa. Natomiast nasycenie koloru zielonego zrealizowano jako funkcję kwadratową z miejscami zerowymi występującymi dla skrajnych wartości temperatury (zimno, gorąco) oraz ekstremum przypadające mniej więcej w połowie zakresu temperatur. Po wyliczeniu nasycenia poszczególnych składowych, wywoływane jest makro, grupujące poszczególne kolory w jedną 32-bitową zmienną reprezentującą wszystkie składowe kolorów. Funkcja rgb_set_color() (list. 6), przesyłająca wartości kolorów do układu PCA9633 wywoływana jest jedynie wtedy, gdy nastąpiła zmiana nasycenia w stosunku do poprzedniego cyklu.

List. 6. Funkcja modyfikująca kolor wyświetlany na LED-RGB 

 

 
Działanie funkcji ustawiającej nasycenie jest bardzo proste i sprowadza się do przesłania wartości nasycenia kolorów do rejestrów (PWM0…PWM3), w wyniku czego następuje ustawienie odpowiedniego koloru diody LED.
W rzeczywistej aplikacji termometru należy poszerzyć zakres temperatur ciepło-zimno, można także pomyśleć o wyznaczeniu różnych wartości ciepło-zimno w zależności od pory roku itp.
Lucjan Bryndza
www.boff.pl

Do pobrania

Autor: