Blog >
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.
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.
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.
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”:
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:
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.
Comments
Good insights on .NET. I’m curious if it’s suitable for low-power devices.