- Löschen einer Aufgabe in FreeRTOS Arduino
- Was ist die Warteschlange in FreeRTOS?
- Erstellen einer Warteschlange in FreeRTOS
- Schaltplan
- Implementierung der FreeRTOS-Warteschlange in der Arduino IDE
Im vorherigen Tutorial haben wir FreeRTOS in Arduino Uno eingeführt und eine Aufgabe für die blinkende LED erstellt. In diesem Tutorial werden wir uns nun eingehender mit fortgeschrittenen Konzepten von RTOS-APIs befassen und mehr über die Kommunikation zwischen verschiedenen Aufgaben erfahren. Hier erfahren Sie auch mehr über die Warteschlange zum Übertragen von Daten von einer Aufgabe zur anderen und demonstrieren die Funktionsweise von Warteschlangen-APIs durch die Verbindung von 16x2 LCD und LDR mit dem Arduino Uno.
Bevor wir uns mit Warteschlangen befassen, sehen wir uns eine weitere FreeRTOS-API an, die beim Löschen der Aufgaben hilfreich ist, wenn die zugewiesene Arbeit abgeschlossen ist. Manchmal muss die Aufgabe gelöscht werden, um den zugewiesenen Speicher freizugeben. In Fortsetzung des vorherigen Tutorials verwenden wir die API-Funktion vTaskDelete () im selben Code, um eine der Aufgaben zu löschen. Eine Aufgabe kann die API-Funktion vTaskDelete () verwenden, um sich selbst oder eine andere Aufgabe zu löschen.
Um diese API verwenden zu können, müssen Sie die Datei FreeRTOSConfig.h konfigurieren. Diese Datei wird verwendet, um FreeRTOS entsprechend der Anwendung anzupassen. Es wird verwendet, um die Planungsalgorithmen und viele andere Parameter zu ändern. Die Datei befindet sich im Arduino-Verzeichnis, das allgemein im Ordner "Dokumente" Ihres PCs verfügbar ist. In meinem Fall ist es wie unten gezeigt unter \ Documents \ Arduino \ library \ FreeRTOS \ src verfügbar.
Nun öffnen Sie diese Datei mit einem beliebigen Texteditor und der Suche nach dem #define INCLUDE_vTaskDelete und stellen Sie sicher, dass ihr Wert ‚1‘(1 Mittel ermöglichen und 0 bedeutet deaktivieren). Es ist standardmäßig 1, prüft es jedoch.
Wir werden diese Konfigurationsdatei in unseren nächsten Tutorials häufig zum Einstellen der Parameter verwenden.
Lassen Sie uns nun sehen, wie Sie eine Aufgabe löschen.
Löschen einer Aufgabe in FreeRTOS Arduino
Um eine Aufgabe zu löschen, müssen wir die API-Funktion vTaskDelete () verwenden. Es braucht nur ein Argument.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Dies ist das Handle der Aufgabe, die gelöscht werden soll. Es ist das gleiche wie das 6 - te Argument xTaskCreate () API. Im vorherigen Lernprogramm wurde dieses Argument als NULL festgelegt. Sie können jedoch die Adresse des Inhalts der Aufgabe unter Verwendung eines beliebigen Namens übergeben. Angenommen, Sie möchten das Task-Handle für Task2 festlegen, das als deklariert ist
TaskHandle_t any_name; Beispiel: TaskHandle_t xTask2Handle;
Nun, in vTaskCreate () API - Satz 6 - ten Argument
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1 & xTask2Handle);
Auf den Inhalt dieser Aufgabe kann jetzt mit dem von Ihnen angegebenen Handle zugegriffen werden.
Eine Aufgabe kann sich auch selbst löschen, indem NULL anstelle eines gültigen Aufgabenhandles übergeben wird.
Wenn wir Task 3 aus Task 3 selbst löschen möchten, müssen Sie vTaskDelete (NULL) schreiben . innerhalb der Task3-Funktion, aber wenn Sie Task 3 aus Task 2 löschen möchten, schreiben Sie vTaskDelete (xTask3Handle); innerhalb der task2-Funktion.
Um im vorherigen Tutorial-Code Task2 aus Task2 selbst zu löschen, fügen Sie einfach vTaskDelete (NULL) hinzu. in der Funktion void TaskBlink2 (void * pvParameters) . Dann sieht die obige Funktion so aus
void TaskBlink2 (void * pvParameters) { Serial.println ("Task2 wird ausgeführt und wird gerade gelöscht"); vTaskDelete (NULL); PinMode (7, OUTPUT); während (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digital (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Laden Sie nun den Code hoch und beobachten Sie die LEDs und den seriellen Monitor. Sie werden sehen, dass die zweite LED jetzt nicht blinkt und task2 nach dem Aufrufen der Lösch-API gelöscht wird.
Diese API kann also verwendet werden, um die Ausführung der jeweiligen Aufgabe zu stoppen.
Beginnen wir jetzt mit der Warteschlange.
Was ist die Warteschlange in FreeRTOS?
Warteschlange ist die Datenstruktur, die die endliche Anzahl von Elementen fester Größe enthalten kann, und sie wird im FIFO-Schema (First-in First-out) betrieben. Warteschlangen bieten einen Kommunikationsmechanismus von Task zu Task, von Task zu Interrupt und von Interrupt zu Task.
Die maximale Anzahl von Elementen, die die Warteschlange aufnehmen kann, wird als "Länge" bezeichnet. Sowohl die Länge als auch die Größe jedes Elements werden beim Erstellen der Warteschlange festgelegt.
Ein Beispiel dafür, wie die Warteschlange für die Datenübertragung verwendet wird, finden Sie in der FreeRTOS-Dokumentation, die Sie hier finden. Sie können das gegebene Beispiel leicht verstehen.
.Nachdem Sie die Warteschlangen verstanden haben, versuchen wir, den Prozess des Erstellens einer Warteschlange zu verstehen und sie in unseren FreeRTOS-Code zu implementieren.
Erstellen einer Warteschlange in FreeRTOS
Beschreiben Sie zunächst die Problemstellung, die mit Hilfe der FreeRTOS-Warteschlange und von Arduino Uno implementiert werden soll.
Wir möchten den Wert des LDR-Sensors auf einem 16 * 2-LCD drucken. Es gibt also jetzt zwei Aufgaben
- Task1 erhält analoge Werte von LDR.
- Task2 druckt den Analogwert auf dem LCD.
Hier spielt also die Warteschlange ihre Rolle, weil sie die von Task1 generierten Daten an Task2 sendet. In Aufgabe 1 senden wir einen analogen Wert an die Warteschlange und in Aufgabe 2 erhalten wir ihn aus der Warteschlange.
Es gibt drei Funktionen zum Arbeiten mit Warteschlangen
- Erstellen einer Warteschlange
- Senden von Daten an die Warteschlange
- Daten aus der Warteschlange empfangen
Verwenden Sie zum Erstellen einer Warteschlange die Funktions-API xQueueCreate (). Es braucht zwei Argumente.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: Die maximale Anzahl von Elementen, die die erstellte Warteschlange gleichzeitig aufnehmen kann.
uxItemSize: Die Größe jedes Datenelements in Byte, das in der Warteschlange gespeichert werden kann.
Wenn diese Funktion NULL zurückgibt, wird die Warteschlange aufgrund unzureichenden Speichers nicht erstellt. Wenn ein Wert ungleich NULL zurückgegeben wird, wird die Warteschlange erfolgreich erstellt. Speichern Sie diesen Rückgabewert in einer Variablen, um ihn wie unten gezeigt als Handle für den Zugriff auf die Warteschlange zu verwenden.
QueueHandle_t queue1; queue1 = xQueueCreate (4, sizeof (int));
Dadurch wird eine Warteschlange mit 4 Elementen im Heapspeicher der Größe int (2 Byte jedes Blocks) erstellt und der Rückgabewert in der Handle-Variablen queue1 gespeichert .
2. Senden von Daten an die Warteschlange in FreeRTOS
Um die Werte an die Warteschlange zu senden, verfügt FreeRTOS zu diesem Zweck über zwei API-Varianten.
- xQueueSendToBack (): Wird verwendet, um Daten an die Rückseite (Warteschlange) einer Warteschlange zu senden.
- xQueueSendToFront (): Wird verwendet, um Daten an die Vorderseite (Kopf) einer Warteschlange zu senden.
Nun , xQueueSend () entspricht, und genau das gleiche wie xQueueSendToBack ().
Alle diese APIs akzeptieren 3 Argumente.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: Das Handle der Warteschlange, an die die Daten gesendet (geschrieben) werden. Diese Variable entspricht der Speicherung des Rückgabewerts der xQueueCreate-API.
pvItemToQueue: Ein Zeiger auf die Daten, die in die Warteschlange kopiert werden sollen.
xTicksToWait: Die maximale Zeit, die die Aufgabe im Status "Blockiert" verbleiben soll, um darauf zu warten, dass Speicherplatz in der Warteschlange verfügbar wird.
Wenn Sie xTicksToWait auf portMAX_DELAY setzen , wartet die Aufgabe unbegrenzt (ohne Zeitüberschreitung ), sofern INCLUDE_vTaskSuspend in FreeRTOSConfig.h auf 1 gesetzt ist. Andernfalls können Sie das Makro pdMS_TO_TICKS () verwenden , um eine in Millisekunden angegebene Zeit in eine in Ticks angegebene Zeit umzuwandeln.
3. Empfangen von Daten aus der Warteschlange in FreeRTOS
Um ein Element aus einer Warteschlange zu empfangen (zu lesen), wird xQueueReceive () verwendet. Das empfangene Element wird aus der Warteschlange entfernt.
Diese API akzeptiert auch drei Argumente.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Das erste und dritte Argument entsprechen dem Senden der API. Nur das zweite Argument ist anders.
const pvBuffer: Ein Zeiger auf den Speicher, in den die empfangenen Daten kopiert werden.
Ich hoffe, Sie haben die drei APIs verstanden. Jetzt werden wir diese APIs in der Arduino IDE implementieren und versuchen, die oben beschriebene Problemstellung zu lösen.
Schaltplan
So sieht es auf dem Steckbrett aus:
Implementierung der FreeRTOS-Warteschlange in der Arduino IDE
Beginnen wir mit dem Schreiben von Code für unsere Anwendung.
1. Öffnen Sie zuerst die Arduino IDE und fügen Sie die Header-Datei Arduino_FreeRTOS.h hinzu . Wenn nun ein Kernelobjekt wie die Warteschlange verwendet wird, fügen Sie die Headerdatei hinzu. Da wir 16 * 2 LCD verwenden, geben Sie auch die Bibliothek dafür an.
#include #include
2. Initialisieren Sie ein Warteschlangenhandle, um den Inhalt der Warteschlange zu speichern. Initialisieren Sie auch die LCD-Pin-Nummern.
QueueHandle_t queue_1; LiquidCrystal lcd (7, 8, 9, 10, 11, 12);
3. Initialisieren Sie in void setup () LCD und seriellen Monitor mit einer Baudrate von 9600. Erstellen Sie eine Warteschlange und zwei Aufgaben mit den entsprechenden APIs. Hier erstellen wir eine Warteschlange der Größe 4 mit ganzzahligem Typ. Erstellen Sie eine Aufgabe mit gleichen Prioritäten und versuchen Sie später, mit dieser Nummer zu spielen. Starten Sie abschließend den Scheduler wie unten gezeigt.
void setup () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Warteschlange kann nicht erstellt werden"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }}
4. Erstellen Sie nun zwei Funktionen: TaskDisplay und TaskLDR . Lesen Sie in der TaskLDR- Funktion den analogen Pin A0 in einer Variablen, da LDR mit dem A0-Pin von Arduino UNO verbunden ist. Senden Sie nun den in der Variablen gespeicherten Wert, indem Sie ihn in der xQueueSend- API übergeben, und senden Sie die Aufgabe nach 1 Sekunde mithilfe der vTaskDelay () -API in den Blockstatus , wie unten gezeigt.
void TaskLDR (void * pvParameters) { int current_intensity; while (1) { Serial.println ("Task1"); current_intensity = analogRead (A0); Serial.println (current_intensity); xQueueSend (queue_1 & current_intensity, portMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. Erstellen Sie auf ähnliche Weise eine Funktion für TaskDisplay und empfangen Sie die Werte in einer Variablen, die an die Funktion xQueueReceive übergeben wird. Auch xQueueReceive () kehrt pdPASS wenn die Daten erfolgreich von der Warteschlange empfangen werden können, und gibt errQUEUE_EMPTY wenn eine Warteschlange leer ist.
Zeigen Sie nun die Werte mit der Funktion lcd.print () auf dem LCD an.
void TaskDisplay (void * pvParameters) { int Intensität = 0; while (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1 & Intensität, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Intensität:"); lcd.setCursor (11, 0); lcd.print (Intensität); } } }
Das ist es. Wir haben den Codierungsteil der Queue-Implementierung abgeschlossen. Den vollständigen Code mit einem funktionierenden Video finden Sie am Ende.
Verbinden Sie nun das LCD und den LDR mit Arduino UNO gemäß dem Schaltplan. Laden Sie den Code hoch. Öffnen Sie den seriellen Monitor und beobachten Sie die Aufgaben. Sie werden sehen, dass Aufgaben wechseln und sich die LDR-Werte entsprechend der Lichtintensität ändern.
ANMERKUNG: Die meisten Bibliotheken, die für verschiedene Sensoren erstellt wurden, werden vom FreeRTOS-Kernel aufgrund der Implementierung der Verzögerungsfunktion in den Bibliotheken nicht unterstützt. Durch die Verzögerung stoppt die CPU vollständig, daher funktioniert auch der FreeRTOS-Kernel nicht mehr und der Code wird nicht weiter ausgeführt und es beginnt sich schlecht zu verhalten. Wir müssen also die Bibliotheken verzögerungsfrei machen, um mit FreeRTOS arbeiten zu können.