- Eliminazione di un'attività in FreeRTOS Arduino
- Cos'è la coda in FreeRTOS?
- Creazione di una coda in FreeRTOS
- Schema elettrico
- Implementazione della coda FreeRTOS nell'IDE di Arduino
Nel tutorial precedente, abbiamo introdotto FreeRTOS in Arduino Uno e creato un'attività per il LED lampeggiante. Ora, in questo tutorial, approfondiremo i concetti avanzati delle API RTOS e impareremo la comunicazione tra diverse attività. Qui impariamo anche a Queue per trasferire dati da un'attività a un'altra e dimostriamo il funzionamento delle API di coda interfacciando LCD 16x2 e LDR con Arduino Uno.
Prima di parlare delle code, vediamo un'altra API FreeRTOS che è utile per eliminare le attività una volta terminato il lavoro assegnato. A volte l'attività deve essere eliminata per liberare la memoria assegnata. In continuazione del tutorial precedente, utilizzeremo la funzione API vTaskDelete () nello stesso codice per eliminare una delle attività. Un'attività può utilizzare la funzione API vTaskDelete () per eliminare se stessa o qualsiasi altra attività.
Per utilizzare questa API, devi configurare il file FreeRTOSConfig.h . Questo file viene utilizzato per personalizzare FreeRTOS in base all'applicazione. Viene utilizzato per modificare gli algoritmi di pianificazione e molti altri parametri. Il file si trova nella directory Arduino che è generalmente disponibile nella cartella Documenti del tuo PC. Nel mio caso, è disponibile in \ Documents \ Arduino \ libraries \ FreeRTOS \ src come mostrato di seguito.
Ora, aprire questo file utilizzando qualsiasi editor di testo e cercare la # define INCLUDE_vTaskDelete e assicurarsi che il suo valore è '1' (1 significa abilitare e 0 significa disabilita). È 1 per impostazione predefinita, ma lo controlla.
Useremo questo file di configurazione frequentemente nei nostri prossimi tutorial per impostare i parametri.
Vediamo ora come eliminare un'attività.
Eliminazione di un'attività in FreeRTOS Arduino
Per eliminare un'attività, dobbiamo utilizzare la funzione API vTaskDelete (). Ci vuole solo un argomento.
vTaskDelete (TaskHandle_t pxTaskToDelete);
pxTaskToDelete: è l'handle dell'attività che deve essere eliminata. È uguale al 6 ° argomento xTaskCreate () API. Nell'esercitazione precedente, questo argomento è impostato come NULL ma è possibile passare l'indirizzo del contenuto dell'attività utilizzando qualsiasi nome. Supponiamo che tu voglia impostare l'handle dell'attività per Task2 che è dichiarato come
TaskHandle_t any_name; Esempio: TaskHandle_t xTask2Handle;
Ora, in vTaskCreate () API impostato 6 ° argomento come
xTaskCreate (TaskBlink2, "task2", 128, NULL, 1, & xTask2Handle);
È ora possibile accedere al contenuto di questa attività utilizzando l'handle fornito dall'utente.
Inoltre, un'attività può eliminarsi passando NULL al posto di un handle di attività valido.
Se vogliamo eliminare l'attività 3 dall'attività 3 stessa, è necessario scrivere vTaskDelete (NULL); all'interno della funzione Task3 ma se si desidera eliminare l'attività 3 dall'attività 2, scrivere vTaskDelete (xTask3Handle); all'interno della funzione task2.
Nel codice del tutorial precedente, per eliminare Task2 da task2 stesso, aggiungi semplicemente vTaskDelete (NULL); nella funzione void TaskBlink2 (void * pvParameters) . Quindi la funzione sopra sarà simile a questa
void TaskBlink2 (void * pvParameters) { Serial.println ("Task2 è in esecuzione e sta per essere cancellato"); vTaskDelete (NULL); pinMode (7, OUTPUT); while (1) { digitalWrite (7, HIGH); vTaskDelay (300 / portTICK_PERIOD_MS); digitalWrite (7, LOW); vTaskDelay (300 / portTICK_PERIOD_MS); } }
Ora carica il codice e osserva i LED e il monitor seriale. Vedrai che il secondo LED non lampeggia ora e task2 viene eliminato dopo aver incontrato l'API di eliminazione.
Quindi questa API può essere utilizzata per interrompere l'esecuzione di una determinata attività.
Ora iniziamo con la coda.
Cos'è la coda in FreeRTOS?
Queue è la struttura dati che può contenere il numero finito di elementi di dimensione fissa e funziona nello schema FIFO (First-in First-out). Le code forniscono un meccanismo di comunicazione da attività a attività, da attività a interruzione e da interruzione a attività.
Il numero massimo di elementi che la coda può contenere è chiamato "lunghezza". Sia la lunghezza che la dimensione di ogni elemento vengono impostate quando viene creata la coda.
Un esempio di come la coda viene utilizzata per il trasferimento dei dati è illustrato bene nella documentazione di FreeRTOS che può essere trovata qui. Puoi facilmente capire l'esempio fornito.
Dopo aver compreso le code, proviamo a capire il processo di creazione di una coda e proviamo a implementarla nel nostro codice FreeRTOS.
Creazione di una coda in FreeRTOS
Innanzitutto, descrivi la dichiarazione del problema che deve essere implementata con l'aiuto della coda FreeRTOS e di Arduino Uno.
Vogliamo stampare il valore del sensore LDR su un LCD 16 * 2. Quindi ora ci sono due compiti
- Task1 sta ottenendo valori analogici di LDR.
- Task2 sta stampando il valore analogico sull'LCD.
Quindi, qui la coda gioca il suo ruolo perché invia i dati generati da task1 a task2. In task1, invieremo un valore analogico alla coda e in task2, lo riceveremo dalla coda.
Ci sono tre funzioni per lavorare con le code
- Creazione di una coda
- Invio di dati a Queue
- Ricezione di dati da Queue
Per creare la coda, utilizzare l' API della funzione xQueueCreate (). Ci vogliono due argomenti.
xQueueCreate (UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
uxQueueLength: il numero massimo di elementi che la coda in fase di creazione può contenere in qualsiasi momento.
uxItemSize: la dimensione in byte di ogni elemento di dati che può essere archiviato nella coda.
Se questa funzione restituisce NULL, la coda non viene creata a causa della memoria insufficiente e se restituisce un valore diverso da NULL, la coda viene creata correttamente. Memorizza questo valore di ritorno in una variabile per usarlo come handle per accedere alla coda come mostrato di seguito.
QueueHandle_t queue1; queue1 = xQueueCreate (4, sizeof (int));
Questo creerà una coda di 4 elementi nella memoria heap di dimensione int (2 byte di ogni blocco) e memorizzerà il valore di ritorno nella variabile handle queue1 .
2. Invio di dati alla coda in FreeRTOS
Per inviare i valori alla coda, FreeRTOS ha 2 varianti di API per questo scopo.
- xQueueSendToBack (): utilizzato per inviare i dati in fondo (coda) di una coda.
- xQueueSendToFront (): utilizzato per inviare dati all'inizio (head) di una coda.
Ora , xQueueSend () è equivalente ed esattamente uguale a xQueueSendToBack ().
Tutte queste API richiedono 3 argomenti.
xQueueSendToBack (QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);
xQueue: l'handle della coda a cui vengono inviati (scritti) i dati. Questa variabile è la stessa utilizzata per memorizzare il valore restituito dell'API xQueueCreate.
pvItemToQueue: un puntatore ai dati da copiare nella coda.
xTicksToWait: il tempo massimo in cui l'attività deve rimanere nello stato Bloccato per attendere che lo spazio diventi disponibile nella coda.
L'impostazione di xTicksToWait su portMAX_DELAY causerà un'attesa indefinita (senza timeout), a condizione che INCLUDE_vTaskSuspend sia impostato su 1 in FreeRTOSConfig. Altrimenti è possibile utilizzare la macro pdMS_TO_TICKS () per convertire un tempo specificato in millisecondi in un tempo specificato in tick.
3. Ricezione dei dati dalla coda in FreeRTOS
Per ricevere (leggere) un elemento da una coda, viene utilizzato xQueueReceive (). L'elemento ricevuto viene rimosso dalla coda.
Questa API accetta anche tre argomenti.
xQueueReceive (QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait);
Il primo e il terzo argomento sono gli stessi dell'invio dell'API. Solo il secondo argomento è diverso.
const pvBuffer: un puntatore alla memoria in cui verranno copiati i dati ricevuti.
Spero che tu abbia capito le tre API. Ora implementeremo queste API nell'IDE di Arduino e proveremo a risolvere la dichiarazione del problema che abbiamo descritto sopra.
Schema elettrico
Ecco come appare sulla breadboard:
Implementazione della coda FreeRTOS nell'IDE di Arduino
Cominciamo a scrivere il codice per la nostra applicazione.
1. Innanzitutto, apri l'IDE di Arduino e includi il file di intestazione Arduino_FreeRTOS.h . Ora, se viene utilizzato un oggetto del kernel come queue, includi il file di intestazione di esso. Dato che stiamo usando LCD 16 * 2, includi anche la libreria.
#include #include
2. Inizializzare un handle di coda per memorizzare il contenuto della coda. Inoltre, inizializza i numeri dei pin LCD.
QueueHandle_t queue_1; LCD LiquidCrystal (7, 8, 9, 10, 11, 12);
3. In void setup (), inizializza LCD e monitor seriale con 9600 baud rate. Crea una coda e due attività utilizzando le rispettive API. Qui creeremo una coda di dimensione 4 con tipo intero. Crea un'attività con le stesse priorità e in seguito prova a giocare con questo numero. Infine, avvia lo scheduler come mostrato di seguito.
void setup () { Serial.begin (9600); lcd.begin (16, 2); queue_1 = xQueueCreate (4, sizeof (int)); if (queue_1 == NULL) { Serial.println ("La coda non può essere creata"); } xTaskCreate (TaskDisplay, "Display_task", 128, NULL, 1, NULL); xTaskCreate (TaskLDR, "LDR_task", 128, NULL, 1, NULL); vTaskStartScheduler (); }
4. Ora, crea due funzioni TaskDisplay e TaskLDR . Nella funzione TaskLDR , leggi il pin analogico A0 in una variabile poiché abbiamo LDR collegato al pin A0 di Arduino UNO. Ora invia il valore memorizzato nella variabile passandolo nell'API xQueueSend e invia l'attività allo stato di blocco dopo 1 secondo utilizzando l' API vTaskDelay () come mostrato di seguito.
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. Allo stesso modo, creare una funzione per TaskDisplay e ricevere i valori in una variabile passata alla funzione xQueueReceive . Inoltre, xQueueReceive () restituisce pdPASS se i dati possono essere ricevuti con successo dalla coda e restituisce errQUEUE_EMPTY se una coda è vuota.
Ora, visualizza i valori sul display LCD utilizzando la funzione lcd.print () .
void TaskDisplay (void * pvParameters) { int intensità = 0; while (1) { Serial.println ("Task2"); if (xQueueReceive (queue_1, & intense, portMAX_DELAY) == pdPASS) { lcd.clear (); lcd.setCursor (0, 0); lcd.print ("Intensity:"); lcd.setCursor (11, 0); lcd.print (intensità); } } }
Questo è tutto. Abbiamo terminato la parte di codifica dell'implementazione della coda. Il codice completo con un video funzionante può essere trovato alla fine.
Ora collega LCD e LDR con Arduino UNO secondo lo schema elettrico carica il codice. Apri il monitor seriale e osserva le attività. Vedrai che le attività cambiano e i valori LDR cambiano in base all'intensità della luce.
NOTA: la maggior parte delle librerie realizzate per sensori diversi non sono supportate dal kernel FreeRTOS a causa del ritardo nell'implementazione della funzione all'interno delle librerie. Il ritardo fa arrestare completamente la CPU, quindi, anche il kernel FreeRTOS smette di funzionare e il codice non verrà eseguito ulteriormente e inizierà a comportarsi male. Quindi, dobbiamo rendere le librerie senza ritardi per funzionare con FreeRTOS.