- Jak działa RTOS?
- Często używane terminy w RTOS
- Instalowanie biblioteki Arduino FreeRTOS
- Schemat obwodu
- Przykład Arduino FreeRTOS - Tworzenie zadań FreeRTOS w Arduino IDE
- Implementacja zadań FreeRTOS w Arduino IDE
System operacyjny obecny w urządzeniach wbudowanych nosi nazwę RTOS (system operacyjny czasu rzeczywistego). W urządzeniach wbudowanych zadania w czasie rzeczywistym są krytyczne, gdzie synchronizacja odgrywa bardzo ważną rolę. Zadania w czasie rzeczywistym są deterministyczne w czasie, co oznacza, że czas reakcji na dowolne zdarzenie jest zawsze stały, dzięki czemu można zagwarantować, że określone zdarzenie nastąpi w ustalonym czasie. RTOS jest przeznaczony do uruchamiania aplikacji z bardzo precyzyjnym taktowaniem i wysokim stopniem niezawodności. RTOS pomaga również w wielozadaniowości z jednym rdzeniem.
Omówiliśmy już samouczek dotyczący korzystania z RTOS w systemach wbudowanych, w którym można dowiedzieć się więcej o RTOS, różnicach między systemem operacyjnym ogólnego przeznaczenia i RTOS, różnymi typami RTOS itp.
W tym samouczku zaczniemy od FreeRTOS. FreeRTOS to klasa RTOS dla urządzeń wbudowanych, która jest na tyle mała, że można ją uruchomić na 8/16-bitowych mikrokontrolerach, chociaż jej zastosowanie nie ogranicza się do tych mikrokontrolerów. Jest to całkowicie open-source, a jego kod jest dostępny na github. Jeśli znamy kilka podstawowych koncepcji RTOS, to jest bardzo łatwy w użyciu FreeRTOS, ponieważ ma dobrze udokumentowane interfejsy API, które mogą być bezpośrednio użyte w kodzie bez znajomości wewnętrznej części kodowania. Pełną dokumentację FreeRTOS można znaleźć tutaj.
Ponieważ FreeRTOS może działać na 8-bitowym MCU, więc można go również uruchomić na płycie Arduino Uno. Wystarczy pobrać bibliotekę FreeRTOS, a następnie rozpocząć wdrażanie kodu za pomocą interfejsów API. Ten samouczek jest przeznaczony dla całkowicie początkujących, poniżej znajdują się tematy, które omówimy w tym samouczku Arduino FreeRTOS:
- Jak działa RTOS
- Niektóre często używane terminy w systemie RTOS
- Instalowanie FreeRTOS w Arduino IDE
- Jak tworzyć zadania FreeRTOS na przykładzie
Jak działa RTOS?
Zanim zaczniemy pracę z RTOS, zobaczmy, co to jest zadanie. Zadanie to fragment kodu, który można zaplanować w CPU do wykonania. Tak więc, jeśli chcesz wykonać jakieś zadanie, powinno być zaplanowane przy użyciu opóźnienia jądra lub przerwań. Ta praca jest wykonywana przez Harmonogram obecny w jądrze. W procesorze jednordzeniowym program planujący pomaga zadaniom wykonywać je w określonym przedziale czasu, ale wydaje się, że różne zadania są wykonywane jednocześnie. Każde zadanie jest uruchamiane zgodnie z nadanym mu priorytetem.
Teraz zobaczmy, co dzieje się w jądrze RTOS, jeśli chcemy utworzyć zadanie dla diody LED migającej z jednosekundową przerwą i nadać temu zadaniu najwyższy priorytet.
Oprócz zadania LED, będzie jeszcze jedno zadanie, które jest tworzone przez jądro, znane jako zadanie bezczynne. Bezczynne zadanie jest tworzone, gdy żadne zadanie nie jest dostępne do wykonania. To zadanie zawsze działa z najniższym priorytetem, tj. Priorytetem 0. Jeśli przeanalizujemy wykres czasowy podany powyżej, można zauważyć, że wykonanie rozpoczyna się od zadania LED i działa przez określony czas, a następnie przez pozostały czas zadanie bezczynności działa aż do wystąpienia przerwania tikowego. Następnie jądro decyduje, które zadanie ma zostać wykonane zgodnie z priorytetem zadania i łącznym czasem, który upłynął od zadania LED. Po zakończeniu 1 sekundy jądro ponownie wybiera zadanie led do wykonania, ponieważ ma ono wyższy priorytet niż zadanie bezczynności, możemy również powiedzieć, że zadanie LED wyprzedza zadanie bezczynności. Jeśli istnieje więcej niż dwa zadania o tym samym priorytecie, będą one działać w trybie okrężnym przez określony czas.
Poniżej diagramu stanu, ponieważ pokazuje przełączenie niedziałającego zadania w stan uruchomiony.
Każde nowo utworzone zadanie przechodzi w stan Gotowe (część stanu niedziałającego). Jeśli utworzone zadanie (Zadanie1) ma najwyższy priorytet niż inne zadania, przejdzie do stanu uruchomionego. Jeśli to uruchomione zadanie przejdzie przez inne zadanie, ponownie wróci do stanu gotowości. W przeciwnym razie, jeśli zadanie1 zostanie zablokowane przy użyciu blokującego interfejsu API, procesor nie będzie angażował się w to zadanie przed upływem limitu czasu określonego przez użytkownika.
Jeśli zadanie 1 zostanie zawieszone w stanie działania za pomocą funkcji Suspend API, wówczas zadanie 1 przejdzie w stan Suspended i nie będzie ponownie dostępne dla harmonogramu. Jeśli wznowisz Zadanie 1 w stanie wstrzymania, powróci ono do stanu gotowości, jak widać na schemacie blokowym.
To jest podstawowa idea działania zadań i zmiany ich stanów. W tym samouczku zaimplementujemy dwa zadania w Arduino Uno przy użyciu FreeRTOS API.
Często używane terminy w RTOS
1. Zadanie: Jest to fragment kodu, który jest planowany przez procesor do wykonania.
2. Harmonogram: Odpowiada za wybór zadania z listy stanu gotowości do stanu uruchomionego. Harmonogramy są często wdrażane, aby wszystkie zasoby komputera były zajęte (jak w przypadku równoważenia obciążenia).
3. Wyprzedzanie: Jest to czynność czasowego przerwania już wykonywanego zadania z zamiarem wyjęcia go ze stanu uruchomionego bez jego współpracy.
4. Przełączanie kontekstu: W przypadku wywłaszczania opartego na priorytetach, harmonogram porównuje priorytet uruchomionych zadań z priorytetem gotowej listy zadań przy każdym przerwaniu systemowym . Jeśli na liście jest jakieś zadanie, którego priorytet jest wyższy niż uruchomione zadanie, następuje przełączenie kontekstu. Zasadniczo w tym procesie zawartość różnych zadań jest zapisywana w odpowiedniej pamięci stosu.
5. Typy zasad planowania:
- Planowanie zapobiegawcze: w przypadku tego typu planowania zadania są uruchamiane z równym przedziałem czasu bez uwzględniania priorytetów.
- Preemptive oparte na priorytetach: zadanie o wysokim priorytecie zostanie uruchomione jako pierwsze.
- Planowanie kooperacyjne: Przełączanie kontekstu będzie się odbywać tylko przy współpracy uruchomionych zadań. Zadanie będzie działać nieprzerwanie, aż do wywołania wydajności zadania.
6. Obiekty jądra: Do sygnalizowania zadania wykonania jakiejś pracy używany jest proces synchronizacji. Do wykonania tego procesu używane są obiekty jądra. Niektóre obiekty jądra to zdarzenia, semafory, kolejki, muteksy, skrzynki pocztowe itp. Zobaczymy, jak używać tych obiektów w nadchodzących samouczkach.
Z powyższej dyskusji mamy kilka podstawowych pomysłów na temat koncepcji RTOS i teraz możemy zaimplementować projekt FreeRTOS w Arduino. Zacznijmy więc od zainstalowania bibliotek FreeRTOS w Arduino IDE.
Instalowanie biblioteki Arduino FreeRTOS
1. Otwórz Arduino IDE i przejdź do Sketch -> Include Library -> Manage Libraries . Wyszukaj FreeRTOS i zainstaluj bibliotekę, jak pokazano poniżej.
Możesz pobrać bibliotekę z github i dodać plik.zip w Sketch-> Include Library -> Add.zip file.
Teraz uruchom ponownie Arduino IDE. Ta biblioteka zawiera przykładowy kod, który również można znaleźć w Plik -> Przykłady -> FreeRTOS, jak pokazano poniżej.
Tutaj napiszemy kod od podstaw, aby zrozumieć działanie, później możesz sprawdzić przykładowe kody i użyć ich.
Schemat obwodu
Poniżej znajduje się schemat obwodu do tworzenia zadania Migająca dioda LED za pomocą FreeRTOS na Arduino:
Przykład Arduino FreeRTOS - Tworzenie zadań FreeRTOS w Arduino IDE
Zobaczmy podstawową strukturę do napisania projektu FreeRTOS.
1. Najpierw dołącz plik nagłówkowy Arduino FreeRTOS jako
#zawierać
2. Podaj prototyp funkcji wszystkich funkcji, które piszesz do wykonania, który jest zapisany jako
void Zadanie1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Teraz w funkcji void setup () utwórz zadania i uruchom harmonogram zadań.
Aby utworzyć zadanie, w funkcji setup wywoływana jest funkcja xTaskCreate () z określonymi parametrami / argumentami.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Jest 6 argumentów, które należy podać podczas tworzenia dowolnego zadania. Zobaczmy, jakie są te argumenty
- pvTaskCode: jest to po prostu wskaźnik do funkcji, która implementuje zadanie (w efekcie tylko nazwa funkcji).
- pcName: opisowa nazwa zadania. To nie jest używane przez FreeRTOS. Jest dołączony wyłącznie do celów debugowania.
- usStackDepth: Każde zadanie ma swój własny, unikalny stos, który jest przydzielany przez jądro do zadania podczas tworzenia zadania. Wartość określa liczbę słów, które może przechowywać stos, a nie liczbę bajtów. Na przykład, jeśli stos ma 32 bity szerokości, a usStackDepth zostanie przekazane jako 100, wówczas zostanie przydzielone 400 bajtów miejsca na stosie (100 * 4 bajty) w pamięci RAM. Używaj tego mądrze, ponieważ Arduino Uno ma tylko 2 KB pamięci RAM.
- pvParameters: parametr wejściowy zadania (może mieć wartość NULL).
- uxPriority: priorytet zadania (0 to najniższy priorytet).
- pxCreatedTask: może służyć do przekazania uchwytu do tworzonego zadania. Ten uchwyt może następnie służyć do odwoływania się do zadania w wywołaniach interfejsu API, które na przykład zmieniają priorytet zadania lub usuwają zadanie (może mieć wartość NULL).
Przykład tworzenia zadań
xTaskCreate (zadanie1, "zadanie1", 128, NULL, 1, NULL); xTaskCreate (zadanie2, "zadanie2", 128, NULL, 2, NULL);
Tutaj Task2 ma wyższy priorytet i dlatego jest wykonywany jako pierwszy.
4. Po utworzeniu zadania uruchom program planujący w konfiguracji void za pomocą vTaskStartScheduler (); API.
5. Funkcja Void loop () pozostanie pusta, ponieważ nie chcemy uruchamiać żadnego zadania ręcznie i w nieskończoność. Ponieważ wykonywanie zadań jest teraz obsługiwane przez harmonogram.
6. Teraz musimy zaimplementować funkcje zadań i napisać logikę, którą chcesz wykonywać wewnątrz tych funkcji. Nazwa funkcji powinna być taka sama, jak pierwszy argument funkcji API xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..//your logic } }
7. Większość kodu wymaga funkcji opóźnienia, aby zatrzymać uruchomione zadanie, ale w RTOS nie zaleca się używania funkcji Delay (), ponieważ zatrzymuje ona procesor, a zatem RTOS również przestaje działać. Tak więc FreeRTOS ma API jądra do blokowania zadania na określony czas.
vTaskDelay (const TickType_t xTicksToDelay);
Ten interfejs API może być używany do celów opóźnienia. Ten interfejs API opóźnia zadanie o określoną liczbę taktów. Rzeczywisty czas, przez który zadanie pozostaje zablokowane, zależy od wskaźnika tick. Stała portTICK_PERIOD_MS może służyć do obliczania w czasie rzeczywistym na podstawie taktowania .
Oznacza to, że jeśli chcesz opóźnienie 200 ms, po prostu napisz tę linię
vTaskDelay (200 / portTICK_PERIOD_MS);
Dlatego w tym samouczku użyjemy tych interfejsów API FreeRTOS do realizacji trzech zadań.
Interfejsy API do wykorzystania:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Zadanie do utworzenia dla tego samouczka:
- Dioda LED miga na cyfrowym pinie 8 z częstotliwością 200 ms
- Dioda LED miga na cyfrowym pinie 7 z częstotliwością 300 ms
- Wydrukuj numery na monitorze szeregowym z częstotliwością 500 ms.
Implementacja zadań FreeRTOS w Arduino IDE
1. Z powyższego podstawowego wyjaśnienia struktury, dołącz plik nagłówkowy Arduino FreeRTOS. Następnie utwórz prototypy funkcji. Ponieważ mamy trzy zadania, więc wykonaj trzy funkcje i ich prototypy.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. W funkcji void setup () zainicjuj komunikację szeregową z prędkością 9600 bitów na sekundę i utwórz wszystkie trzy zadania za pomocą funkcji API xTaskCreate () . Najpierw ustaw priorytety wszystkich zadań na „1” i uruchom program planujący.
void setup () { Serial.begin (9600); xTaskCreate (TaskBlink1, "Task1", 128, NULL, 1, NULL); xTaskCreate (TaskBlink2, "Task2", 128, NULL, 1, NULL); xTaskCreate (Taskprint, "Task3", 128, NULL, 1, NULL); vTaskStartScheduler (); }
3. Teraz zaimplementuj wszystkie trzy funkcje, jak pokazano poniżej dla migania diody zadania 1.
void TaskBlink1 (void * pvParameters) { pinMode (8, OUTPUT); while (1) { digitalWrite (8, WYSOKI); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, NISKI); vTaskDelay (200 / portTICK_PERIOD_MS); } }
Podobnie zaimplementuj funkcję TaskBlink2. Funkcja Task3 zostanie zapisana jako
void Taskprint (void * pvParameters) { int counter = 0; while (1) { licznik ++; Serial.println (licznik); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Otóż to. Z powodzeniem zakończyliśmy projekt FreeRTOS Arduino dla Arduino Uno. Możesz znaleźć pełny kod wraz z filmem na końcu tego samouczka.
Na koniec podłącz dwie diody LED do cyfrowych pinów 7 i 8 i prześlij kod na swoją płytę Arduino i otwórz monitor szeregowy. Zobaczysz, że licznik działa raz na 500 ms z nazwą zadania, jak pokazano poniżej.
Obserwuj także diody LED, migają one w różnych odstępach czasu. Spróbuj pobawić się argumentem priorytetowym w funkcji xTaskCreate . Zmień numer i obserwuj zachowanie monitora szeregowego i diod LED.
Teraz możesz zrozumieć pierwsze dwa przykładowe kody, w których tworzone są zadania odczytu analogowego i odczytu cyfrowego. W ten sposób możesz tworzyć bardziej zaawansowane projekty, używając tylko interfejsów API Arduino Uno i FreeRTOS.