- Een taak verwijderen in FreeRTOS Arduino
- Wat is de wachtrij in FreeRTOS?
- Een wachtrij maken in FreeRTOS
- Schakelschema
- Implementatie van FreeRTOS Queue in Arduino IDE
In de vorige tutorial hebben we FreeRTOS in Arduino Uno geïntroduceerd en een taak gemaakt voor de knipperende LED. Nu, in deze tutorial, gaan we dieper in op geavanceerde concepten van RTOS API's en leren we over communicatie tussen verschillende taken. Hier leren we ook over Queue om gegevens van de ene taak naar de andere over te dragen en demonstreren we de werking van wachtrij-API's door 16x2 LCD en LDR te koppelen met de Arduino Uno.
Voordat we het hebben over wachtrijen, laten we nog een FreeRTOS API bekijken die handig is bij het verwijderen van de taken wanneer het klaar is met het toegewezen werk. Soms moet de taak worden verwijderd om het toegewezen geheugen vrij te maken. In het verlengde van de vorige tutorial zullen we de vTaskDelete () API-functie in dezelfde code gebruiken om een van de taken te verwijderen. Een taak kan de vTaskDelete () API-functie gebruiken om zichzelf of een andere taak te verwijderen.
Om deze API te gebruiken, moet u het bestand FreeRTOSConfig.h configureren. Dit bestand wordt gebruikt om FreeRTOS aan te passen aan de toepassing. Het wordt gebruikt om de planningsalgoritmen en vele andere parameters te wijzigen. Het bestand is te vinden in de Arduino Directory die algemeen beschikbaar is in de map Documenten van uw pc. In mijn geval is het beschikbaar in \ Documents \ Arduino \ libraries \ FreeRTOS \ src zoals hieronder getoond.
Nu, opent dit bestand met behulp van een tekstverwerker en zoek naar de #define INCLUDE_vTaskDelete en zorg ervoor dat de waarde ervan is '1' (1 betekent ingeschakeld en 0 betekent uitgeschakeld). Het is standaard 1, maar controleert het.
We zullen dit configuratiebestand regelmatig gebruiken in onze volgende tutorials om de parameters in te stellen.
Laten we nu eens kijken hoe we een taak kunnen verwijderen.
Een taak verwijderen in FreeRTOS Arduino
Om een taak te verwijderen, moeten we de vTaskDelete () API-functie gebruiken. Er is maar één argument voor nodig.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: Het is de handle van de taak die moet worden verwijderd. Het is hetzelfde als de 6 e argument van xTaskCreate () API. In de vorige zelfstudie is dit argument ingesteld als NULL, maar u kunt het adres van de inhoud van de taak doorgeven door een willekeurige naam te gebruiken. Stel dat u de taakafhandeling voor Task2 wilt instellen die is gedeclareerd als
TaskHandle_t elke_naam; Voorbeeld: TaskHandle_t xTask2Handle;
Nu, in vTaskCreate () API-set 6 e argument
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1, & xTask2Handle);
De inhoud van deze taak is nu toegankelijk via het door u opgegeven handvat.
Ook kan een taak zichzelf verwijderen door NULL door te geven in plaats van een geldige taakingang.
Als we taak 3 uit taak 3 zelf willen verwijderen, moet u vTaskDelete (NULL) schrijven; binnen de Task3-functie, maar als je taak 3 uit taak 2 wilt verwijderen, schrijf dan vTaskDelete (xTask3Handle); binnen de task2-functie.
In de vorige zelfstudiecode, om Task2 van task2 zelf te verwijderen, voegt u gewoon vTaskDelete (NULL) toe; in ongeldige TaskBlink2 (void * pvParameters) functie. Dan ziet bovenstaande functie er als volgt uit
void TaskBlink2 (void * pvParameters) { Serial.println ("Task2 wordt uitgevoerd en staat op het punt te verwijderen"); vTaskDelete (NULL); pinMode (7, UITGANG); while (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Upload nu de code en bekijk de LED's en de seriële monitor. U zult zien dat de tweede LED nu niet knippert en task2 wordt verwijderd na het tegenkomen van de verwijder-API.
Deze API kan dus worden gebruikt om de uitvoering van de specifieke taak te stoppen.
Laten we nu beginnen met de wachtrij.
Wat is de wachtrij in FreeRTOS?
Wachtrij is de datastructuur die het eindige aantal elementen met vaste grootte kan bevatten en wordt gebruikt in het FIFO-schema (First-in First-out). Wachtrijen bieden een communicatiemechanisme van taak naar taak, taak om te onderbreken en onderbreken naar taak.
Het maximale aantal elementen dat de wachtrij kan bevatten, wordt de "lengte" genoemd. Zowel de lengte als de grootte van elk element worden ingesteld wanneer de wachtrij wordt gemaakt.
Een voorbeeld van hoe de wachtrij wordt gebruikt voor gegevensoverdracht, wordt goed geïllustreerd in de FreeRTOS-documentatie die hier te vinden is. U kunt het gegeven voorbeeld gemakkelijk begrijpen.
Het is een feit dat u zich geen zorgen hoeft te maken.Laten we, nadat we de wachtrijen hebben begrepen, proberen het proces van het maken van een wachtrij te begrijpen en proberen deze in onze FreeRTOS-code te implementeren.
Een wachtrij maken in FreeRTOS
Beschrijf eerst de probleemstelling die moet worden geïmplementeerd met behulp van de FreeRTOS-wachtrij en Arduino Uno.
We willen de waarde van de LDR-sensor afdrukken op een 16 * 2 LCD-scherm. Er zijn dus nu twee taken
- Task1 krijgt analoge waarden van LDR.
- Task2 drukt de analoge waarde af op het LCD-scherm.
Dus hier speelt de wachtrij zijn rol omdat de door task1 gegenereerde gegevens naar task2 worden verzonden. In task1 sturen we analoge waarde naar de wachtrij en in task2 ontvangen we deze uit de wachtrij.
Er zijn drie functies om met wachtrijen te werken
- Een wachtrij maken
- Gegevens naar wachtrij verzenden
- Gegevens ontvangen van wachtrij
Gebruik de functie-API van xQueueCreate () om een wachtrij te maken. Er zijn twee argumenten voor nodig.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: het maximale aantal items dat de wachtrij die wordt gemaakt, tegelijkertijd kan bevatten.
uxItemSize: de grootte in bytes van elk gegevensitem dat in de wachtrij kan worden opgeslagen.
Als deze functie NULL retourneert, wordt de wachtrij niet gemaakt vanwege onvoldoende geheugen en als deze een niet-NULL-waarde retourneert, wordt de wachtrij met succes gemaakt. Sla deze geretourneerde waarde op in een variabele om deze als een handvat te gebruiken om toegang te krijgen tot de wachtrij, zoals hieronder wordt weergegeven.
QueueHandle_t wachtrij1; wachtrij1 = xQueueCreate (4, sizeof (int));
Dit zal een wachtrij met 4 elementen in het heap-geheugen van int-grootte creëren (2 bytes van elk blok) en de retourwaarde opslaan in de variabele queue1 handle.
2. Gegevens naar wachtrij verzenden in FreeRTOS
Om de waarden naar de wachtrij te sturen, heeft FreeRTOS hiervoor 2 API-varianten.
- xQueueSendToBack (): wordt gebruikt om gegevens naar de achterkant (staart) van een wachtrij te sturen.
- xQueueSendToFront (): wordt gebruikt om gegevens naar de voorkant (hoofd) van een wachtrij te sturen.
Nu is xQueueSend () gelijk aan, en precies hetzelfde als, xQueueSendToBack ().
Al deze API's hebben 3 argumenten nodig.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: De handle van de wachtrij waarnaar de gegevens worden verzonden (geschreven). Deze variabele is dezelfde als die wordt gebruikt om de retourwaarde van xQueueCreate API op te slaan.
pvItemToQueue: een pointer naar de gegevens die naar de wachtrij moeten worden gekopieerd.
xTicksToWait: de maximale hoeveelheid tijd dat de taak in de status Geblokkeerd moet blijven om te wachten tot er ruimte in de wachtrij beschikbaar komt.
Door xTicksToWait in te stellen op portMAX_DELAY zal de taak voor onbepaalde tijd wachten (zonder time-out), op voorwaarde dat INCLUDE_vTaskSuspend is ingesteld op 1 in FreeRTOSConfig. Anders kun je de macro pdMS_TO_TICKS () gebruiken om een tijd gespecificeerd in milliseconden om te zetten in een tijd gespecificeerd in tikken.
3. Gegevens ontvangen van wachtrij in FreeRTOS
Om een item uit een wachtrij te ontvangen (lezen), wordt xQueueReceive () gebruikt. Het item dat wordt ontvangen, wordt uit de wachtrij verwijderd.
Deze API heeft ook drie argumenten.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Eerste en derde argumenten zijn hetzelfde als het verzenden van API. Alleen het tweede argument is anders.
const pvBuffer: Een pointer naar het geheugen waarin de ontvangen gegevens zullen worden gekopieerd.
Ik hoop dat je de drie API's hebt begrepen. Nu zullen we deze API's in de Arduino IDE implementeren en proberen de probleemstelling op te lossen die we hierboven hebben beschreven.
Schakelschema
Dit is hoe het eruit ziet op het breadboard:
Implementatie van FreeRTOS Queue in Arduino IDE
Laten we beginnen met het schrijven van code voor onze applicatie.
1. Open eerst Arduino IDE en voeg het Arduino_FreeRTOS.h header-bestand toe. Als nu een kernelobject zoals wachtrij wordt gebruikt, voeg dan het headerbestand ervan toe. Omdat we 16 * 2 LCD-schermen gebruiken, neemt u er ook de bibliotheek voor op.
#include #include
2. Initialiseer een wachtrijhandgreep om de inhoud van de wachtrij op te slaan. Initialiseer ook LCD-pincodes.
QueueHandle_t queue_1; LiquidCrystal lcd (7, 8, 9, 10, 11, 12);
3. Initialiseer in lege setup () de LCD en seriële monitor met een baudrate van 9600. Maak een wachtrij en twee taken met behulp van de respectieve API's. Hier maken we een wachtrij van grootte 4 met een integer-type. Maak een taak met dezelfde prioriteiten en probeer later met dit nummer te spelen. Start ten slotte de planner zoals hieronder weergegeven.
ongeldige setup () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("Wachtrij kan niet worden aangemaakt"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Maak nu twee functies TaskDisplay en TaskLDR . Lees in de TaskLDR- functie analoge pin A0 in een variabele, aangezien we LDR hebben aangesloten op de A0-pin van Arduino UNO. Verzend nu de waarde die is opgeslagen in de variabele door deze door te geven in de xQueueSend API en stuur de taak na 1 seconde naar de blokstatus met behulp van de vTaskDelay () API, zoals hieronder wordt weergegeven.
void TaskLDR (void * pvParameters) { int current_intensity; while (1) { Serial.println ("Task1"); current_intensity = analogRead (A0); Serial.println (current_intensity); xQueueSend (wachtrij_1, & current_intensity, portMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. Maak op dezelfde manier een functie voor TaskDisplay en ontvang de waarden in een variabele die wordt doorgegeven aan de functie xQueueReceive . Ook retourneert xQueueReceive () pdPASS als de gegevens met succes uit de wachtrij kunnen worden ontvangen en retourneert errQUEUE_EMPTY als een wachtrij leeg is.
Geef nu de waarden weer op het LCD-scherm met de functie lcd.print () .
void TaskDisplay (void * pvParameters) { int intensiteit = 0; while (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1, & intensiteit, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Intensiteit:"); lcd.setCursor (11, 0); lcd.print (intensiteit); } } }
Dat is het. We zijn klaar met het coderen van de Queue-implementatie. Volledige code met een werkende video is te vinden aan het einde.
Verbind nu de LCD en LDR met Arduino UNO volgens het schakelschema en upload de code. Open de seriële monitor en observeer de taken. Je zult zien dat taken wisselen en LDR-waarden veranderen naargelang de lichtintensiteit.
OPMERKING: De meeste bibliotheken die voor verschillende sensoren zijn gemaakt, worden niet ondersteund door de FreeRTOS-kernel vanwege de vertraagde functie-implementatie in de bibliotheken. Vertraging zorgt ervoor dat de CPU volledig stopt, daarom stopt de FreeRTOS-kernel ook met werken en zal de code niet verder worden uitgevoerd en begint hij zich te misdragen. We moeten de bibliotheken dus vertragingsvrij maken om met FreeRTOS te werken.