- Supressió d'una tasca a FreeRTOS Arduino
- Què és la cua a FreeRTOS?
- Creació d’una cua a FreeRTOS
- Esquema de connexions
- Implementació de la cua FreeRTOS a Arduino IDE
Al tutorial anterior, vam introduir FreeRTOS a Arduino Uno i vam crear una tasca per al LED parpellejant. Ara, en aquest tutorial, ens endinsarem més en conceptes avançats de les API RTOS i coneixerem la comunicació entre diferents tasques. Aquí també aprenem sobre la cua per transferir dades d’una tasca a una altra i demostrem el funcionament de les API de la cua mitjançant la interfície de 16x2 LCD i LDR amb l’Arduino Uno.
Abans de debatre sobre les cues, vegem una API FreeRTOS més que és útil per suprimir les tasques quan finalitzi amb el treball assignat. De vegades, cal eliminar la tasca per alliberar la memòria assignada. A continuació del tutorial anterior, utilitzarem la funció API vTaskDelete () al mateix codi per suprimir una de les tasques. Una tasca pot utilitzar la funció API vTaskDelete () per suprimir-se, o qualsevol altra tasca.
Per utilitzar aquesta API, heu de configurar el fitxer FreeRTOSConfig.h . Aquest fitxer s'utilitza per adaptar FreeRTOS segons l'aplicació. S'utilitza per canviar els algoritmes de planificació i molts altres paràmetres. El fitxer es troba al directori Arduino, que generalment està disponible a la carpeta Documents del vostre PC. En el meu cas, està disponible a \ Documents \ Arduino \ libraries \ FreeRTOS \ src com es mostra a continuació.

Ara, obre aquest arxiu amb qualsevol editor de text i la recerca de la #define INCLUDE_vTaskDelete i assegureu-vos que el seu valor és '1' (1 significa habilitar i 0 significa desactivar). Per defecte és 1, però ho comprova.

Utilitzarem aquest fitxer de configuració amb freqüència als nostres propers tutorials per establir els paràmetres.
Ara, vegem com esborra una tasca.
Supressió d'una tasca a FreeRTOS Arduino
Per suprimir una tasca, hem d’utilitzar la funció API vTaskDelete (). Només cal un argument.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: és el controlador de la tasca que s'ha de suprimir. És el mateix que el 6 º argument de xTaskCreate () API. Al tutorial anterior, aquest argument s'estableix com a NULL, però podeu passar l'adreça del contingut de la tasca utilitzant qualsevol nom. Digueu si voleu establir el controlador de tasques per a la tasca 2 que es declara com a
TaskHandle_t any_name; Exemple: TaskHandle_t xTask2Handle;
Ara, en vTaskCreate () de l'API estableix 6 º argument com
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1 i & xTask2Handle);
Ara es pot accedir al contingut d'aquesta tasca mitjançant el controlador que heu proporcionat.
A més, una tasca es pot suprimir passant NULL en lloc d'un identificador de tasca vàlid.
Si volem eliminar la tasca 3 de la pròpia tasca 3, heu d’escriure vTaskDelete (NULL); dins de la funció Task3, però si voleu eliminar la tasca 3 de la tasca 2, escriviu vTaskDelete (xTask3Handle); dins de la funció task2.
Al codi del tutorial anterior, per eliminar Task2 de la pròpia task2 , només cal afegir vTaskDelete (NULL); in void TaskBlink2 (void * pvParameters) funció. Aleshores, la funció anterior es mostrarà així
void TaskBlink2 (void * pvParameters) { Serial.println ("La tasca2 s'està executant i està a punt de suprimir-se"); vTaskDelete (NULL); pinMode (7, OUTPUT); while (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Ara, pengeu el codi i observeu els LED i el monitor sèrie. Veureu que el segon LED no parpelleja ara i que la tasca 2 s’elimina després de trobar l’API d’eliminació.

Per tant, aquesta API es pot utilitzar per aturar l'execució de la tasca en particular.
Ara comencem per la cua.
Què és la cua a FreeRTOS?
La cua és l'estructura de dades que pot contenir el nombre finit d'elements de mida fixa i s'utilitza en l'esquema FIFO (First-in First-out). Les cues proporcionen un mecanisme de comunicació de tasca a tasca, tasca a interrompre i interrupció a tasca.
El nombre màxim d'elements que pot contenir la cua s'anomena "longitud". Tant la longitud com la mida de cada element es defineixen quan es crea la cua.
Un exemple de com s’utilitza la cua per a la transferència de dades s’il·lustra bé a la documentació de FreeRTOS que es pot trobar aquí. Podeu entendre fàcilment l’exemple donat.

Després d’entendre les cues, intentem entendre el procés de creació d’una cua i intentem implementar-la al nostre codi FreeRTOS.
Creació d’una cua a FreeRTOS
En primer lloc, descriviu la declaració de problema que s'ha d'implementar amb l'ajut de la cua FreeRTOS i Arduino Uno.
Volem imprimir el valor del sensor LDR a 16 * 2 LCD. Per tant, ara hi ha dues tasques
- La tasca 1 obté valors analògics de LDR.
- La tasca 2 imprimeix el valor analògic a la pantalla LCD.
Per tant, aquí la cua té el seu paper perquè enviar les dades generades per task1 a task2. A la tasca 1, enviarem valor analògic a la cua i a la tasca 2, la rebrem de la cua.
Hi ha tres funcions per treballar amb cues
- Creació d'una cua
- S'estan enviant les dades a la cua
- Rebent dades de la cua
Per crear cua, utilitzeu l' API de funció xQueueCreate (). Calen dos arguments.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: nombre màxim d'elements que pot contenir la cua que s'està creant alhora.
uxItemSize: la mida en bytes de cada element de dades que es pot emmagatzemar a la cua.
Si aquesta funció retorna NULL, la cua no es crea a causa de la memòria insuficient i si retorna un valor que no és NULL, la cua es crea correctament. Emmagatzemeu aquest valor de retorn a una variable per utilitzar-lo com a controlador per accedir a la cua, tal com es mostra a continuació.
QueueHandle_t queue1; cua1 = xQueueCreate (4, sizeof (int));
Això crearà una cua de 4 elements a la memòria dinàmica de mida int (2 bytes de cada bloc) i emmagatzemarà el valor de retorn a la variable de control de queue1 .
2. Enviament de dades a la cua a FreeRTOS
Per enviar els valors a la cua, FreeRTOS té 2 variants d'API amb aquest propòsit.
- xQueueSendToBack (): s’utilitza per enviar dades a la part posterior (cua) d’una cua.
- xQueueSendToFront (): s’utilitza per enviar dades a la part frontal (capçalera) d’una cua.
Ara , xQueueSend () equival a xQueueSendToBack () i és exactament igual .
Totes aquestes API tenen 3 arguments.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: el controlador de la cua a la qual s’envien les dades (escrites). Aquesta variable és la mateixa que s'utilitza per emmagatzemar el valor de retorn de l'API xQueueCreate.
pvItemToQueue: un punter a les dades que es copiaran a la cua.
xTicksToWait: la quantitat màxima de temps que la tasca ha de romandre en estat Bloquejat per esperar que l'espai estigui disponible a la cua.
Si configureu xTicksToWait a portMAX_DELAY , la tasca s’espera indefinidament (sense esgotar el temps), sempre que INCLUDE_vTaskSuspend estigui establerta a 1 a FreeRTOSConfig.h; en cas contrari, podeu utilitzar la macro pdMS_TO_TICKS () per convertir un temps especificat en mil·lisegons en un temps especificat en ticks.
3. Rebre dades de la cua a FreeRTOS
Per rebre (llegir) un element d'una cua, s'utilitza xQueueReceive (). L'element que es rep s'elimina de la cua.
Aquesta API també té tres arguments.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
El primer i el tercer arguments són els mateixos que enviar API. Només el segon argument és diferent.
const pvBuffer: un punter cap a la memòria on es copiaran les dades rebudes.
Espero que hàgiu entès les tres API. Ara implementarem aquestes API a l’IDE Arduino i intentarem resoldre la declaració de problema que hem descrit anteriorment.
Esquema de connexions

Així es veu a la pissarra:

Implementació de la cua FreeRTOS a Arduino IDE
Comencem a escriure codi per a la nostra aplicació.
1. Primer, obriu Arduino IDE i incloeu el fitxer de capçalera Arduino_FreeRTOS.h . Ara, si s’utilitza algun objecte del nucli com la cua, incloeu-hi el fitxer de capçalera. Com que fem servir 16 * 2 LCD, incloeu-hi també la biblioteca.
#include #include
2. Inicialitzeu un controlador de cua per emmagatzemar el contingut de la cua. A més, inicialitzeu els números dels pins LCD.
QueueHandle_t queue_1; LiquidCrystal lcd (7, 8, 9, 10, 11, 12);
3. En configuració nul·la (), inicialitzeu el monitor LCD i el serial amb una velocitat de 9600 baud. Creeu una cua i dues tasques mitjançant les API corresponents. Aquí crearem una cua de mida 4 amb tipus enter. Creeu una tasca amb les mateixes prioritats i més endavant proveu de jugar amb aquest número. Finalment, inicieu el planificador com es mostra a continuació.
configuració nul·la () { Serial.begin (9600); lcd.begin (16, 2); cua_1 = xQueueCreate (4, sizeof (int)); if (cua_1 == NULL) { Serial.println ("La cua no es pot crear"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Ara, feu dues funcions TaskDisplay i TaskLDR . A la funció TaskLDR , llegiu el pin analògic A0 en una variable ja que tenim LDR connectat al pin A0 d'Arduino UNO. Ara envieu el valor emmagatzemat a la variable passant-lo a l' API xQueueSend i envieu la tasca a l'estat de bloqueig després d'1 segon mitjançant l' API vTaskDelay () com es mostra a continuació.
void TaskLDR (void * pvParameters) { int current_intensity; while (1) { Serial.println ("Tasca1"); intensitat_actual = Llegiranalògic (A0); Serial.println (intensitat_actual); xQueueSend (cua_1, & intensitat_actual, portMAX_DELAY); vTaskDelay (1000 / portTICK_PERIOD_MS); } }
5. De la mateixa manera, feu una funció per a TaskDisplay i rebeu els valors d'una variable que es passa a la funció xQueueReceive . A més, xQueueReceive () retorna pdPASS si les dades es poden rebre amb èxit des de la cua i retorna errQUEUE_EMPTY si una cua està buida.
Ara, mostreu els valors a la pantalla LCD mitjançant la funció lcd.print () .
void TaskDisplay (void * pvParameters) { int intensitat = 0; while (1) { Serial.println ("Tasca2"); if (xQueueReceive (cua_1, & intensitat, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Intensitat:"); lcd.setCursor (11, 0); lcd.print (intensitat); } } }
Això és. Hem acabat la part de codificació de la implementació de la cua. Al final trobareu un codi complet amb un vídeo que funciona.
Ara, connecteu el LCD i el LDR amb Arduino UNO segons el diagrama del circuit, carregueu el codi. Obriu el monitor sèrie i observeu les tasques. Veureu que les tasques canvien i els valors de LDR canvien segons la intensitat de la llum.


NOTA: La majoria de les biblioteques creades per a diferents sensors no són compatibles amb el nucli FreeRTOS a causa de la implementació de la funció de retard a les biblioteques. El retard fa que la CPU s’aturi completament, per tant, el nucli FreeRTOS també deixa de funcionar i el codi no s’executarà més i comença a comportar-se malament. Per tant, hem de fer que les biblioteques siguin lliures de retard per treballar amb el FreeRTOS.
