Blog

.NET w programowaniu systemów wbudowanych

5
min czytania
Down arrow button

Blog >

.NET w programowaniu systemów wbudowanych
TechInsights

Obecnie, używając ekosystemu .NET możemy wytwarzać oprogramowanie na różne platformy, począwszy od podstawowego zastosowania jakim jest tworzenie backendów aplikacji webowych, poprzez aplikacje desktopowe, skończywszy na aplikacjach mobilnych dla systemów Android i iOS. Czy możliwe jest jednak pisanie w .NET-cie oprogramowania dla systemów wbudowanych, w przypadku których zasoby sprzętowe w postaci ilości dostępnej pamięci operacyjnej i mocy obliczeniowej procesora bywają mocno ograniczone? 

Programowanie systemów wbudowanych, opartych o 8 lub 32-bitowe mikrokontrolery może kojarzyć się z koniecznością używania języków niższego poziomu niż C#, takich jak C/C++. Okazuje się jednak, że dzięki .NET nanoFramework możemy, z użyciem języka C#, tworzyć oprogramowanie działające na takich popularnych rodzinach mikrokontrolerów jak ESP32 czy STM32. 

W tym artykule zaprezentuję przykład użycia nanoFrameworka oraz ESP32 do budowy prostego modułu stacji pogodowej, umożliwiającego pomiar temperatury, ciśnienia i wilgotności powietrza.

Czym jest nanoFramework i dlaczego warto go poznać?

nanoFramework jest platformą umożliwiającą pisanie kodu w języku C# działającego na wielu rodzinach mikrokontrolerów. Kluczowym modułem jest nanoCLR – implementacja maszyny wirtualnej języka C# (ang. Common Language Runtime, CLR) przeznaczona specjalnie dla mikrokontrolerów. 

nanoCLR implementuje tylko część standardu języka C# i API jego biblioteki standardowej głównie ze względu na bardzo ograniczone zasoby sprzętowe, którymi dysponują mikrokontrolery. Braki te nie stanowią jednak poważnego ograniczenia. Programista nadal może korzystać z takich udogodnień jak na przykład mechanizm automatycznej dealokacji pamięci (ang. garbage collection) czy składnia związana z obiektowym paradygmatem programowania (klasy, struktury, polimorfizm, itp.). W założeniu przyspiesza to tworzenie oprogramowania w porównaniu do użycia języka C/C++, zwłaszcza w sytuacji, kiedy programista nie posiada dużego doświadczenia w programowaniu systemów wbudowanych.

Charakterystyka mikrokontrolera ESP32

ESP32 jest 32-bitowym mikrokontrolerem produkowanym przez firmę Espressif Systems od 2016 roku. To następca 8-bitowego mikrokontrolera ESP8266, który tak jak swój poprzednik, szybko zdobył dużą popularność dzięki dobrej relacji ceny do oferowanych możliwości. Mikrokontroler został zaprojektowany między innymi dla zastosowań w urządzeniach ubieralnych (ang. wearable electronics), a także dla rozwiązań z zakresu Internetu rzeczy.

Jedną z jego głównych zalet jest zintegrowany interfejs Bluetooth Low Energy oraz WiFi. Umożliwia to łatwą integrację urządzeń opartych o ten mikrokontroler w rozwiązaniach z zakresu Internetu rzeczy. ESP32 jest powszechnie dostępny na rynku w postaci płytek prototypowych z zintegrowanym interfejsem USB.

Tego typu moduły sprawdzają się idealnie do tworzenia prototypów ze względu na łatwość zasilania i programowania mikrokontrolera poprzez interfejs USB oraz wyprowadzenie wszystkich portów wejścia-wyjścia pod postacią pinów GPIO.

nanoFramework dla ESP32 - konfiguracja środowiska programistycznego

Do pracy z nanoFrameworkiem najprościej wykorzystać IDE Visual Studio. Twórcy frameworka dostarczają odpowiednia wtyczkę dostępną w Visual Studio Market Place . Wtyczka ta umożliwia wygodne wgrywanie kodu do mikrokontrolera oraz jego debuggowanie. Potrzebujemy również narzędzia nanoff umożliwiającego wgranie odpowiedniej wersji nanoFrameworka do pamięci mikrokontrolera. 

Posiadając płytkę prototypową z mikrokontrolerem ESP32 (np. ESP-WROOM-32 dostępny w wielu sklepach z podzespołami elektronicznymi) możemy przystąpić do pracy. Po podpięciu jej do komputera poprzez port USB sprawdzamy w menadżerze urządzeń, jaki numer portu został jej przypisany:

Na powyższym przykładzie widzimy, że numer portu to COM4. Następnie używamy narzędzia nanoff aby wgrać do mikrokontrolera najnowszą wersję nanoframeworka używając polecenia:

nanoff --update --target ESP32_PSRAM_REV0 --serialport COM4

Jeśli operacja przebiegnie poprawnie, zostanie wyświetlony stosowny komunikat:

Po wgraniu nanoFrameworka do mikrokontrolera powinien on być wykrywany w Visual Studio z poziomu sekcji „Device Explorer”, która jest dostępna w zakładce „View” -> „Other Windows” po instalacji pluginu:

Możemy następnie utworzyć nowy projekt z poziomu kreatora Visual Studio:

Nowy projekt domyślnie będzie posiadał implementację aplikacji typu „Hello world”:

Możemy teraz wgrać projekt do mikrokontrolera i uruchomić w trybie debuggowania w taki sam sposób, jak każdy inny projekt w Visual Studio. Jeśli operacja przebiegnie poprawnie, na wyjściu konsoli debuggowania zobaczymy napis „Hello from nanoFramework”:

nanoFramework dla ESP32 - implementacja prostej stacji pogodowej

Aby nasz mikrokontroler mógł dokonywać pomiarów temperatury, ciśnienia i wilgotności, potrzebne są odpowiednie czujniki i ich podłączenie do mikrokontrolera poprzez jego porty wejścia/wyjścia. Bardzo popularnym czujnikiem, który umożliwia pomiar jednocześnie tych 3 parametrów jest BME280 firmy Bosch. Jest szeroko dostępny na rynku, również w postaci płytki prototypowej:

BME280 do komunikacji z mikrokontrolerem używa magistrali I2C lub SPI. Schemat podłączenia tego czujnika do płytki prototypowej mikrokontrolera ESP32 poprzez magistralę I2C może wyglądać następująco:

Linię danych (SDA, połączenie oznaczone kolorem zielonym) podłączamy do portu 2, a linię sygnału zegarowego (SCL, połączenie oznaczone kolorem niebieskim) do portu 22 mikrokontrolera. Czujnik zasilany jest napięciem 3,3V wyprowadzonym z odpowiedniego pinu płytki prototypowej (połączenie oznaczone kolorem czerwonym). 

Aby nawiązać komunikację pomiędzy ESP32 i BME280 potrzebujemy odpowiedniego sterownika. Nie musimy jednak implementować własnego rozwiązania w oparciu o dokumentację BME280 bowiem w pakiecie Nuget Iot.Device.Bmxx80 dostępny jest gotowy sterownik dla tego czujnika. Po dodaniu tego pakietu do naszego projektu w Visual Studio możemy skonfigurować komunikację z czujnikiem:

Najpierw należy skonfigurować określone piny mikrokontrolera (w tym przypadku piny 21 i 22) jako porty danych (SDA) i sygnału zegarowego (SCL) magistrali I2C. Następnie tworzymy konfigurację urządzenia dla magistrali I2C i przekazujemy ją do konstruktora klasy Bme280 reprezentującej sterownik czujnika BME280. Na końcu, w nieskończonej pętli, co każde 5 sekund odczytujemy wartości zmierzonej temperatury, ciśnienia i wilgotności z czujnika i przesyłamy wartości pomiarów jako sformatowany string na standardowe wyjście. 

Po wgraniu tego prostego programu do pamięci mikrokontrolera i uruchomieniu go w trybie debugowania mikrokontroler zacznie co 5 sekund wypisywać na standardowe wyjście wyniki pomiarów:

nanoFramework – zalety i ograniczenia

Największą zaletą nanoFrameworka jest niski próg wejścia dla programistów, którzy dobrze znają język C# i ekosystem .NET ale nie mają doświadczenia w programowaniu mikrokontrolerów z użyciem najpowszechniej używanych w tym przypadku języków C i C++. Dzięki temu programista może skoncentrować się głównie na implementacji logiki biznesowej przy użyciu wysokopoziomowego języka C#, a nie zagłębianiu się w niuanse SDK dla konkretnego mikrokontrolera. 

Do wad nanoFrameworka należy zaliczyć przede wszystkim to, że dodaje on sporą, dodatkową warstwę abstrakcji do oprogramowania działającego na mikrokontrolerze. W przypadku użycia języków C/C++ kod jest kompilowany bezpośrednio do kodu maszynowego wykonywanego przez CPU mikrokontrolera. W przypadku nanoFrameworka kod napisany w języku C# nie jest kompilowany do kodu maszynowego, lecz do kodu pośredniego (ang. Common Intermediate Language, CIL), który następnie jest wykonywany przez maszynę wirtualną. Może to mieć znaczący wpływ na wydajność w przypadku, kiedy kod wykonywany jest na mikrokontrolerze, czyli środowisku z natury wyposażonym w bardzo ograniczone zasoby (pamięć RAM, wydajność CPU).

Przedstawiony w artykule przykład użycia nanoFrameworka jest bardzo prosty. Czy można użyć tej platformy do implementacji znacznie bardziej skomplikowanego rozwiązania? Rozwijając pierwotny pomysł, w kolejnym artykule z tej serii przedstawię możliwości nanoFrameworka i ESP32 w zakresie integracji z usługą Azure IoT Hub. Pozwoli to na implementację dwustronnej komunikacji mikrokontrolera z dowolnymi innymi usługami działającymi w chmurze Azure.

O autorze
Kamil Mrzygłód