- Wie funktioniert RTOS?
- Häufig verwendete Begriffe in RTOS
- Installieren der Arduino FreeRTOS-Bibliothek
- Schaltplan
- Arduino FreeRTOS Beispiel - Erstellen von FreeRTOS-Aufgaben in Arduino IDE
- Implementierung von FreeRTOS-Aufgaben in Arduino IDE
Das in den eingebetteten Geräten vorhandene Betriebssystem wird als RTOS (Real-Time Operating System) bezeichnet. In eingebetteten Geräten sind Echtzeitaufgaben von entscheidender Bedeutung, wenn das Timing eine sehr wichtige Rolle spielt. Echtzeitaufgaben sind zeitdeterministisch bedeutet, dass die Reaktionszeit auf ein Ereignis immer konstant ist, sodass garantiert werden kann, dass ein bestimmtes Ereignis zu einem festgelegten Zeitpunkt auftritt. RTOS wurde entwickelt, um Anwendungen mit sehr genauem Timing und einem hohen Maß an Zuverlässigkeit auszuführen. RTOS hilft auch beim Multitasking mit einem einzigen Kern.
Wir haben bereits ein Tutorial zur Verwendung von RTOS in eingebetteten Systemen behandelt, in dem Sie mehr über RTOS, den Unterschied zwischen Allzweck-Betriebssystemen und RTOS, verschiedene Arten von RTOS usw. erfahren können.
In diesem Tutorial beginnen wir mit FreeRTOS. FreeRTOS ist eine RTOS-Klasse für eingebettete Geräte, die klein genug ist, um auf 8/16-Bit-Mikrocontrollern ausgeführt zu werden, obwohl ihre Verwendung nicht auf diese Mikrocontroller beschränkt ist. Es ist vollständig Open Source und der Code ist auf Github verfügbar. Wenn wir einige grundlegende Konzepte von RTOS kennen, ist es sehr einfach, FreeRTOS zu verwenden, da es gut dokumentierte APIs enthält, die direkt im Code verwendet werden können, ohne den Backend-Teil der Codierung zu kennen. Die vollständige FreeRTOS-Dokumentation finden Sie hier.
Da FreeRTOS auf einer 8-Bit-MCU ausgeführt werden kann, kann es auch auf einem Arduino Uno-Board ausgeführt werden. Wir müssen nur die FreeRTOS-Bibliothek herunterladen und dann mit der Implementierung des Codes mithilfe von APIs beginnen. Dieses Tutorial ist für Anfänger gedacht. Nachfolgend finden Sie die Themen, die wir in diesem Arduino FreeRTOS-Tutorial behandeln werden:
- Wie RTOS funktioniert
- Einige häufig verwendete Begriffe in RTOS
- Installation von FreeRTOS in der Arduino IDE
- So erstellen Sie FreeRTOS-Aufgaben anhand eines Beispiels
Wie funktioniert RTOS?
Bevor Sie mit der Arbeit mit RTOS beginnen, schauen wir uns an, was eine Aufgabe ist. Task ist ein Code, dessen Ausführung auf der CPU planbar ist. Wenn Sie also eine Aufgabe ausführen möchten, sollte sie mithilfe der Kernelverzögerung oder mithilfe von Interrupts geplant werden. Diese Arbeit wird von Scheduler ausgeführt, der im Kernel vorhanden ist. In einem Single-Core-Prozessor hilft der Scheduler bei der Ausführung von Aufgaben in einer bestimmten Zeitscheibe, aber es scheint, als würden verschiedene Aufgaben gleichzeitig ausgeführt. Jede Aufgabe wird gemäß der ihr zugewiesenen Priorität ausgeführt.
Lassen Sie uns nun sehen, was im RTOS-Kernel passiert, wenn wir eine Aufgabe für das Blinken der LED im Abstand von einer Sekunde erstellen und diese Aufgabe auf die höchste Priorität setzen möchten.
Neben der LED-Aufgabe gibt es noch eine weitere Aufgabe, die vom Kernel erstellt wird. Diese Aufgabe wird als Leerlaufaufgabe bezeichnet. Die Leerlaufaufgabe wird erstellt, wenn keine Aufgabe zur Ausführung verfügbar ist. Diese Aufgabe wird immer mit der niedrigsten Priorität ausgeführt, dh mit der Priorität 0. Wenn wir das oben angegebene Timing-Diagramm analysieren, ist ersichtlich, dass die Ausführung mit einer LED-Task beginnt und für eine bestimmte Zeit ausgeführt wird. Für die verbleibende Zeit wird die Leerlauf-Task ausgeführt, bis ein Tick-Interrupt auftritt. Dann entscheidet der Kernel, welche Aufgabe gemäß der Priorität der Aufgabe und der insgesamt verstrichenen Zeit der LED-Aufgabe ausgeführt werden muss. Wenn 1 Sekunde abgeschlossen ist, wählt der Kernel die geführte Aufgabe erneut aus, um sie auszuführen, da sie eine höhere Priorität als die Leerlaufaufgabe hat. Wir können auch sagen, dass die LED-Aufgabe die Leerlaufaufgabe vorwegnimmt. Wenn es mehr als zwei Aufgaben mit derselben Priorität gibt, werden sie für eine bestimmte Zeit im Round-Robin-Verfahren ausgeführt.
Unterhalb des Zustandsdiagramms zeigt es das Umschalten der nicht laufenden Aufgabe in den laufenden Zustand.
Jede neu erstellte Aufgabe wird in den Status "Bereit" versetzt (Teil des Status "Nicht ausgeführt"). Wenn die erstellte Aufgabe (Aufgabe1) die höchste Priorität als andere Aufgaben hat, wird sie in den laufenden Zustand versetzt. Wenn diese laufende Aufgabe von der anderen Aufgabe vorgezogen wird, kehrt sie wieder in den Bereitschaftszustand zurück. Andernfalls, wenn Task1 mithilfe der Blockierungs-API blockiert wird, wird die CPU diese Task erst nach dem vom Benutzer festgelegten Zeitlimit ausführen.
Wenn Task1 mithilfe von Suspend-APIs im laufenden Zustand angehalten wird, wechselt Task1 in den angehaltenen Zustand und steht dem Scheduler nicht wieder zur Verfügung. Wenn Sie Task1 im angehaltenen Zustand fortsetzen, kehrt es in den Bereitschaftszustand zurück, wie Sie im Blockdiagramm sehen können.
Dies ist die Grundidee, wie Aufgaben ausgeführt werden und ihren Status ändern. In diesem Tutorial werden zwei Aufgaben in Arduino Uno mithilfe der FreeRTOS-API implementiert.
Häufig verwendete Begriffe in RTOS
1. Aufgabe: Es handelt sich um einen Code, dessen Ausführung auf der CPU planbar ist.
2. Scheduler: Er ist dafür verantwortlich, eine Aufgabe aus der Bereitschaftsstatusliste in den laufenden Status auszuwählen. Scheduler werden häufig implementiert, damit alle Computerressourcen ausgelastet sind (wie beim Lastausgleich).
3. Vorkaufsrecht: Es handelt sich um das vorübergehende Unterbrechen einer bereits ausgeführten Aufgabe mit der Absicht, sie ohne ihre Mitarbeit aus dem laufenden Zustand zu entfernen.
4. Kontextwechsel: Bei der prioritätsbasierten Vorauszahlung vergleicht der Scheduler die Priorität der Ausführung von Aufgaben mit der Priorität der Liste der bereitstehenden Aufgaben bei jedem Systick- Interrupt. Wenn die Liste eine Aufgabe enthält, deren Priorität höher ist als die ausgeführte Aufgabe, erfolgt ein Kontextwechsel. Grundsätzlich werden dabei Inhalte verschiedener Aufgaben in ihrem jeweiligen Stack-Speicher gespeichert.
5. Arten von Planungsrichtlinien:
- Präventive Planung: Bei dieser Art der Planung werden Aufgaben mit gleicher Zeitscheibe ausgeführt, ohne die Prioritäten zu berücksichtigen.
- Prioritätsbasiertes Präventiv: Die Aufgabe mit hoher Priorität wird zuerst ausgeführt.
- Kooperative Planung: Die Kontextumschaltung erfolgt nur in Zusammenarbeit mit laufenden Aufgaben. Die Aufgabe wird kontinuierlich ausgeführt, bis die Aufgabenausbeute aufgerufen wird.
6. Kernel-Objekte: Um der Aufgabe zu signalisieren, dass sie einige Arbeiten ausführen soll, wird der Synchronisationsprozess verwendet. Um diesen Prozess auszuführen, werden Kernel-Objekte verwendet. Einige Kernel-Objekte sind Ereignisse, Semaphoren, Warteschlangen, Mutex, Postfächer usw. In den kommenden Tutorials werden wir sehen, wie diese Objekte verwendet werden.
Aus der obigen Diskussion haben wir einige grundlegende Ideen zum RTOS-Konzept und jetzt können wir das FreeRTOS-Projekt in Arduino implementieren. Beginnen wir also mit der Installation von FreeRTOS-Bibliotheken in Arduino IDE.
Installieren der Arduino FreeRTOS-Bibliothek
1. Öffnen Sie die Arduino IDE und gehen Sie zu Skizze -> Bibliothek einschließen -> Bibliotheken verwalten . Suchen Sie nach FreeRTOS und installieren Sie die Bibliothek wie unten gezeigt.
Sie können die Bibliothek von github herunterladen und die ZIP-Datei unter Skizze-> Bibliothek einschließen -> ZIP- Datei hinzufügen hinzufügen .
Starten Sie nun die Arduino IDE neu. Diese Bibliothek enthält einen Beispielcode, der sich auch unter Datei -> Beispiele -> FreeRTOS befindet (siehe unten).
Hier schreiben wir den Code von Grund auf neu, um die Funktionsweise zu verstehen. Später können Sie die Beispielcodes überprüfen und verwenden.
Schaltplan
Unten sehen Sie den Schaltplan zum Erstellen einer blinkenden LED-Aufgabe mit FreeRTOS auf Arduino:
Arduino FreeRTOS Beispiel - Erstellen von FreeRTOS-Aufgaben in Arduino IDE
Sehen wir uns eine Grundstruktur zum Schreiben eines FreeRTOS-Projekts an.
1. Fügen Sie zunächst die Arduino FreeRTOS-Headerdatei als ein
#einschließen
2. Geben Sie den Funktionsprototyp aller Funktionen an, die Sie zur Ausführung schreiben und die als geschrieben sind
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Erstellen Sie nun in der Funktion void setup () Aufgaben und starten Sie den Aufgabenplaner.
Zum Erstellen einer Aufgabe wird die xTaskCreate () - API in der Setup- Funktion mit bestimmten Parametern / Argumenten aufgerufen.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Es gibt 6 Argumente, die beim Erstellen einer Aufgabe übergeben werden sollten. Mal sehen, was diese Argumente sind
- pvTaskCode: Es ist einfach ein Zeiger auf die Funktion, die die Aufgabe implementiert (im Grunde nur der Name der Funktion).
- pcName: Ein beschreibender Name für die Aufgabe. Dies wird von FreeRTOS nicht verwendet. Es ist nur zu Debugging-Zwecken enthalten.
- usStackDepth: Jede Aufgabe verfügt über einen eigenen eindeutigen Stapel, der vom Kernel der Aufgabe beim Erstellen der Aufgabe zugewiesen wird. Der Wert gibt die Anzahl der Wörter an, die der Stapel enthalten kann, nicht die Anzahl der Bytes. Wenn der Stapel beispielsweise 32 Bit breit ist und usStackDepth als 100 übergeben wird, werden 400 Byte Stapelspeicher (100 * 4 Byte) im RAM zugewiesen. Verwenden Sie dies mit Bedacht, da Arduino Uno nur 2 KB RAM hat.
- pvParameters: Task-Eingabeparameter (kann NULL sein).
- uxPriority: Priorität der Aufgabe (0 ist die niedrigste Priorität).
- pxCreatedTask: Es kann verwendet werden, um ein Handle an die zu erstellende Aufgabe zu übergeben. Dieses Handle kann dann verwendet werden, um auf die Aufgabe in API-Aufrufen zu verweisen, die beispielsweise die Aufgabenpriorität ändern oder die Aufgabe löschen (kann NULL sein).
Beispiel für die Erstellung von Aufgaben
xTaskCreate (Aufgabe1, "Aufgabe1", 128, NULL, 1, NULL); xTaskCreate (task2, "task2", 128, NULL, 2, NULL);
Hier hat Task2 eine höhere Priorität und wird daher zuerst ausgeführt.
4. Starten Sie nach dem Erstellen der Aufgabe den Scheduler in einem ungültigen Setup mit vTaskStartScheduler (). API.
5. Die Funktion Void loop () bleibt leer, da wir keine Aufgabe manuell und unendlich ausführen möchten. Weil die Aufgabenausführung jetzt vom Scheduler übernommen wird.
6. Jetzt müssen wir Aufgabenfunktionen implementieren und die Logik schreiben, die Sie in diesen Funktionen ausführen möchten. Der Funktionsname sollte mit dem ersten Argument der xTaskCreate () - API übereinstimmen .
void task1 (void * pvParameters) { while (1) { .. ..//Ihre Logik } }
7. Der größte Teil des Codes benötigt eine Verzögerungsfunktion, um die laufende Aufgabe zu stoppen. In RTOS wird jedoch nicht empfohlen, die Funktion Delay () zu verwenden, da die CPU gestoppt wird und RTOS daher auch nicht mehr funktioniert. FreeRTOS verfügt also über eine Kernel-API, um die Aufgabe für eine bestimmte Zeit zu blockieren.
vTaskDelay (const TickType_t xTicksToDelay);
Diese API kann für Verzögerungszwecke verwendet werden. Diese API verzögert eine Aufgabe für eine bestimmte Anzahl von Ticks. Die tatsächliche Zeit, für die die Aufgabe blockiert bleibt, hängt von der Tickrate ab. Die Konstante portTICK_PERIOD_MS kann verwendet werden, um Echtzeit aus der Tick-Rate zu berechnen.
Das heißt, wenn Sie eine Verzögerung von 200 ms wünschen, schreiben Sie einfach diese Zeile
vTaskDelay (200 / portTICK_PERIOD_MS);
In diesem Tutorial werden wir diese FreeRTOS-APIs verwenden, um drei Aufgaben zu implementieren.
Zu verwendende APIs:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Aufgabe, die für dieses Tutorial erstellt werden soll:
- LED blinkt an Digital Pin 8 mit einer Frequenz von 200 ms
- LED blinkt an Digital Pin 7 mit einer Frequenz von 300 ms
- Drucken Sie die Nummern im seriellen Monitor mit einer Frequenz von 500 ms.
Implementierung von FreeRTOS-Aufgaben in Arduino IDE
1. Fügen Sie aus der obigen Erklärung der Grundstruktur die Arduino FreeRTOS-Headerdatei hinzu. Dann machen Sie Funktionsprototypen. Da wir drei Aufgaben haben, machen Sie drei Funktionen und ihre Prototypen.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. Initialisieren Sie in der Funktion void setup () die serielle Kommunikation mit 9600 Bit pro Sekunde und erstellen Sie alle drei Aufgaben mit der xTaskCreate () -API . Legen Sie zunächst die Prioritäten aller Aufgaben als '1' fest und starten Sie den Scheduler.
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. Implementieren Sie nun alle drei Funktionen wie unten für das Blinken der LED für Aufgabe 1 gezeigt.
void TaskBlink1 (void * pvParameters) { pinMode (8, OUTPUT); while (1) { digitalWrite (8, HIGH); vTaskDelay (200 / portTICK_PERIOD_MS); digitalWrite (8, LOW); vTaskDelay (200 / portTICK_PERIOD_MS); } }
Implementieren Sie auf ähnliche Weise die TaskBlink2-Funktion. Die Task3-Funktion wird als geschrieben
void Taskprint (void * pvParameters) { int counter = 0; while (1) { counter ++; Serial.println (Zähler); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Das ist es. Wir haben ein FreeRTOS Arduino- Projekt für Arduino Uno erfolgreich abgeschlossen. Den vollständigen Code sowie ein Video finden Sie am Ende dieses Tutorials.
Schließen Sie abschließend zwei LEDs an den digitalen Pins 7 und 8 an, laden Sie den Code auf Ihre Arduino-Karte hoch und öffnen Sie den seriellen Monitor. Sie werden sehen, dass ein Zähler einmal in 500 ms mit dem unten gezeigten Aufgabennamen ausgeführt wird.
Beachten Sie auch die LEDs, die in unterschiedlichen Zeitintervallen blinken. Versuchen Sie, mit dem Prioritätsargument in der Funktion xTaskCreate zu spielen. Ändern Sie die Nummer und beobachten Sie das Verhalten auf dem seriellen Monitor und den LEDs.
Jetzt können Sie die ersten beiden Beispielcodes verstehen, in denen analoge und digitale Leseaufgaben erstellt werden. Auf diese Weise können Sie mit nur Arduino Uno- und FreeRTOS-APIs fortgeschrittenere Projekte erstellen.