- Come funziona RTOS?
- Termini usati di frequente in RTOS
- Installazione della libreria Arduino FreeRTOS
- Schema elettrico
- Esempio di Arduino FreeRTOS: creazione di attività FreeRTOS nell'IDE di Arduino
- Implementazione di attività FreeRTOS nell'IDE di Arduino
Il sistema operativo presente all'interno dei dispositivi embedded è chiamato RTOS (Real-Time Operating System). Nei dispositivi integrati, le attività in tempo reale sono fondamentali in cui la tempistica gioca un ruolo molto importante. Le attività in tempo reale sono deterministiche del tempo: il tempo di risposta a qualsiasi evento è sempre costante in modo che sia possibile garantire che un determinato evento si verifichi in un momento fisso. RTOS è progettato per eseguire applicazioni con tempi molto precisi e un alto grado di affidabilità. RTOS aiuta anche nel multi-tasking con un singolo core.
Abbiamo già coperto un tutorial su come utilizzare RTOS in sistemi embedded in cui puoi saperne di più su RTOS, la differenza tra sistema operativo generico e RTOS, diversi tipi di RTOS, ecc.
In questo tutorial, inizieremo con FreeRTOS. FreeRTOS è una classe di RTOS per dispositivi embedded che è abbastanza piccola da essere eseguita su microcontrollori a 8/16 bit, sebbene il suo utilizzo non sia limitato a questi microcontrollori. È completamente open source e il suo codice è disponibile su GitHub. Se conosciamo alcuni concetti di base di RTOS, allora è molto facile usare FreeRTOS perché ha API ben documentate che possono essere utilizzate direttamente nel codice senza conoscere la parte backend della codifica. La documentazione completa di FreeRTOS può essere trovata qui.
Poiché FreeRTOS può essere eseguito su MCU a 8 bit, può essere eseguito anche su scheda Arduino Uno. Dobbiamo solo scaricare la libreria FreeRTOS e quindi iniziare a implementare il codice utilizzando le API. Questo tutorial è pensato per un principiante assoluto, di seguito sono riportati gli argomenti, che tratteremo in questo tutorial Arduino FreeRTOS:
- Come funziona RTOS
- Alcuni termini usati di frequente in RTOS
- Installazione di FreeRTOS nell'IDE di Arduino
- Come creare attività FreeRTOS con esempio
Come funziona RTOS?
Prima di iniziare a lavorare con RTOS, vediamo cos'è un Task. L'attività è un pezzo di codice che può essere eseguito sulla CPU. Quindi, se vuoi eseguire qualche operazione, allora dovrebbe essere pianificata usando il ritardo del kernel o usando gli interrupt. Questo lavoro viene svolto dallo Scheduler presente nel kernel. In un processore single-core, lo scheduler aiuta le attività ad essere eseguite in un particolare intervallo di tempo, ma sembra che diverse attività vengano eseguite contemporaneamente. Ogni attività viene eseguita in base alla priorità assegnata.
Ora, vediamo cosa succede nel kernel RTOS se vogliamo creare un'attività per il LED lampeggiante con un intervallo di un secondo e mettere questa attività alla massima priorità.
Oltre all'attività LED, ci sarà un'altra attività creata dal kernel, nota come attività inattiva. L'attività inattiva viene creata quando nessuna attività è disponibile per l'esecuzione. Questa attività viene eseguita sempre con la priorità più bassa, ovvero priorità 0. Se analizziamo il grafico di temporizzazione fornito sopra, si può vedere che l'esecuzione inizia con un'attività LED e viene eseguita per un tempo specificato, quindi per il tempo rimanente, l'attività inattiva viene eseguita fino a quando non si verifica un interrupt tick. Quindi il kernel decide quale attività deve essere eseguita in base alla priorità dell'attività e al tempo totale trascorso dell'attività LED. Quando 1 secondo è completato, il kernel sceglie di nuovo l'attività principale da eseguire perché ha una priorità più alta rispetto all'attività inattiva, possiamo anche dire che l'attività LED prevale l'attività inattiva. Se sono presenti più di due attività con la stessa priorità, verranno eseguite in modalità round-robin per un periodo di tempo specificato.
Di seguito il diagramma di stato che mostra il passaggio dell'attività non in esecuzione allo stato di esecuzione.
Ogni attività appena creata va nello stato Pronto (parte dello stato non in esecuzione). Se l'attività creata (Attività1) ha la priorità più alta rispetto ad altre attività, passerà allo stato di esecuzione. Se questa attività in esecuzione prevale sull'altra attività, tornerà allo stato pronto. Altrimenti, se l'attività1 viene bloccata utilizzando l'API di blocco, la CPU non si impegnerà in questa attività fino al timeout definito dall'utente.
Se Task1 viene sospeso nello stato di esecuzione utilizzando le API di sospensione, Task1 passerà allo stato Suspended e non sarà nuovamente disponibile per lo scheduler. Se riprendi Task1 nello stato sospeso, tornerà allo stato pronto come puoi vedere nello schema a blocchi.
Questa è l' idea di base di come le attività vengono eseguite e cambiano i loro stati. In questo tutorial, implementeremo due attività in Arduino Uno utilizzando l'API FreeRTOS.
Termini usati di frequente in RTOS
1. Compito: è un pezzo di codice che può essere eseguito sulla CPU.
2. Scheduler: è responsabile della selezione di un'attività dall'elenco di stato pronto allo stato in esecuzione. Gli scheduler sono spesso implementati in modo da mantenere occupate tutte le risorse del computer (come nel bilanciamento del carico).
3. Preemption: è l'atto di interrompere temporaneamente un compito già in esecuzione con l'intenzione di rimuoverlo dallo stato in esecuzione senza la sua cooperazione.
4. cambio di contesto: In prelazione basato su priorità, lo scheduler paragona la priorità delle attività in esecuzione con una priorità di elenco di attività pronta su ogni systick interrupt. Se nell'elenco è presente un'attività la cui priorità è maggiore dell'attività in esecuzione, si verifica il cambio di contesto. Fondamentalmente, in questo processo i contenuti di diverse attività vengono salvati nella rispettiva memoria dello stack.
5. Tipi di criteri di pianificazione:
- Pianificazione preventiva: in questo tipo di pianificazione, le attività vengono eseguite con lo stesso intervallo di tempo senza considerare le priorità.
- Preemptive basato su priorità: l'attività ad alta priorità verrà eseguita per prima.
- Pianificazione cooperativa: il cambio di contesto avverrà solo con la cooperazione delle attività in esecuzione. L'attività verrà eseguita continuamente fino a quando non viene chiamata la resa dell'attività.
6. Oggetti del kernel: per segnalare all'attività di eseguire alcune operazioni, viene utilizzato il processo di sincronizzazione. Per eseguire questo processo vengono utilizzati gli oggetti del kernel. Alcuni oggetti del kernel sono eventi, semafori, code, mutex, cassette postali, ecc. Vedremo come utilizzare questi oggetti nei prossimi tutorial.
Dalla discussione sopra, abbiamo avuto alcune idee di base sul concetto di RTOS e ora possiamo implementare il progetto FreeRTOS in Arduino. Quindi, iniziamo installando le librerie FreeRTOS nell'IDE di Arduino.
Installazione della libreria Arduino FreeRTOS
1. Apri l'IDE di Arduino e vai su Sketch -> Include Library -> Manage Libraries . Cerca FreeRTOS e installa la libreria come mostrato di seguito.
Puoi scaricare la libreria da GitHub e aggiungere il file.zip in Sketch-> Includi libreria -> Aggiungi file .zip .
Ora riavvia l'IDE di Arduino. Questa libreria fornisce un codice di esempio, anch'esso disponibile in File -> Esempi -> FreeRTOS come mostrato di seguito.
Qui scriveremo il codice da zero per capirne il funzionamento, in seguito potrai controllare i codici di esempio e utilizzarli.
Schema elettrico
Di seguito è riportato lo schema del circuito per la creazione di un'attività LED lampeggiante utilizzando FreeRTOS su Arduino:
Esempio di Arduino FreeRTOS: creazione di attività FreeRTOS nell'IDE di Arduino
Vediamo una struttura di base per scrivere un progetto FreeRTOS.
1. Innanzitutto, includi il file di intestazione Arduino FreeRTOS come file
#includere
2. Fornire il prototipo di funzione di tutte le funzioni che si stanno scrivendo per l'esecuzione che è scritto come
void Task1 (void * pvParameters); void Task2 (void * pvParameters); .. ….
3. Ora, nella funzione void setup () , creare attività e avviare l'utilità di pianificazione.
Per creare attività, l' API xTaskCreate () viene chiamata nella funzione di configurazione con determinati parametri / argomenti.
xTaskCreate (TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void * pvParameters, UBaseType_t uxPriority, TaskHandle_t * pxCreatedTask);
Ci sono 6 argomenti che dovrebbero essere passati durante la creazione di qualsiasi attività. Vediamo quali sono questi argomenti
- pvTaskCode: è semplicemente un puntatore alla funzione che implementa l'attività (in effetti, solo il nome della funzione).
- pcName: un nome descrittivo per l'attività. Non è utilizzato da FreeRTOS. È incluso esclusivamente a scopo di debug.
- usStackDepth: ogni attività ha il proprio stack univoco assegnato dal kernel all'attività quando l'attività viene creata. Il valore specifica il numero di parole che lo stack può contenere, non il numero di byte. Ad esempio, se lo stack è largo 32 bit e usStackDepth viene passato come 100, verranno allocati 400 byte di spazio dello stack (100 * 4 byte) nella RAM. Usa questo con saggezza perché Arduino Uno ha solo 2Kbyte di RAM.
- pvParameters: parametro di input dell'attività (può essere NULL).
- uxPriority: priorità dell'attività (0 è la priorità più bassa).
- pxCreatedTask: può essere utilizzato per distribuire un handle all'attività da creare. Questo handle può quindi essere utilizzato per fare riferimento all'attività nelle chiamate API che, ad esempio, modificano la priorità dell'attività o eliminano l'attività (può essere NULL).
Esempio di creazione di attività
xTaskCreate (task1, "task1", 128, NULL, 1, NULL); xTaskCreate (task2, "task2", 128, NULL, 2, NULL);
Qui, Task2 ha una priorità più alta e quindi viene eseguito per primo.
4. Dopo aver creato l'attività, avviare lo scheduler in una configurazione void utilizzando vTaskStartScheduler (); API.
5. La funzione Void loop () rimarrà vuota poiché non vogliamo eseguire alcuna attività manualmente e all'infinito. Perché l'esecuzione dell'attività è ora gestita dallo Scheduler.
6. Ora dobbiamo implementare le funzioni task e scrivere la logica che vuoi eseguire all'interno di queste funzioni. Il nome della funzione dovrebbe essere lo stesso del primo argomento dell'API xTaskCreate () .
void task1 (void * pvParameters) { while (1) { .. ..//your logic } }
7. La maggior parte del codice necessita della funzione di ritardo per interrompere l'attività in esecuzione, ma in RTOS non è consigliabile utilizzare la funzione Delay () poiché arresta la CPU e quindi anche RTOS smette di funzionare. Quindi FreeRTOS ha un'API del kernel per bloccare l'attività per un tempo specifico.
vTaskDelay (const TickType_t xTicksToDelay);
Questa API può essere utilizzata per scopi di ritardo. Questa API ritarda un'attività per un determinato numero di tick. Il tempo effettivo per il quale l'attività rimane bloccata dipende dalla frequenza di tick. La costante portTICK_PERIOD_MS può essere utilizzata per calcolare in tempo reale dal tick rate.
Ciò significa che se desideri un ritardo di 200 ms, scrivi questa riga
vTaskDelay (200 / portTICK_PERIOD_MS);
Quindi, per questo tutorial, useremo queste API FreeRTOS per implementare tre attività.
API da utilizzare:
- xTaskCreate ();
- vTaskStartScheduler ();
- vTaskDelay ();
Attività da creare per questo tutorial:
- Il LED lampeggia sul pin digitale 8 con una frequenza di 200 ms
- Il LED lampeggia al pin digitale 7 con una frequenza di 300 ms
- Stampa i numeri nel monitor seriale con una frequenza di 500 ms.
Implementazione di attività FreeRTOS nell'IDE di Arduino
1. Dalla spiegazione della struttura di base sopra, includi il file di intestazione Arduino FreeRTOS. Quindi crea prototipi di funzioni. Dato che abbiamo tre compiti, crea tre funzioni ed è prototipi.
#include void TaskBlink1 (void * pvParameters); void TaskBlink2 (void * pvParameters); void Taskprint (void * pvParameters);
2. Nella funzione void setup () , inizializza la comunicazione seriale a 9600 bit al secondo e crea tutte e tre le attività utilizzando xTaskCreate () API. Inizialmente, imposta le priorità di tutte le attività su "1" e avvia lo 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. Ora, implementare tutte e tre le funzioni come mostrato di seguito per task1 LED lampeggiante.
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); } }
Allo stesso modo, implementa la funzione TaskBlink2. La funzione Task3 verrà scritta come
void Taskprint (void * pvParameters) { int counter = 0; while (1) { counter ++; Serial.println (contatore); vTaskDelay (500 / portTICK_PERIOD_MS); } }
Questo è tutto. Abbiamo completato con successo un progetto FreeRTOS Arduino per Arduino Uno. Puoi trovare il codice completo insieme a un video alla fine di questo tutorial.
Infine, collega due LED al pin digitale 7 e 8 e carica il codice sulla tua scheda Arduino e apri il monitor seriale. Vedrai un contatore in esecuzione una volta ogni 500 ms con il nome dell'attività come mostrato di seguito.
Inoltre, osserva i LED, lampeggiano a intervalli di tempo diversi. Prova a giocare con l'argomento priorità nella funzione xTaskCreate . Modificare il numero e osservare il comportamento sul monitor seriale e sui LED.
È ora possibile comprendere i primi due codici di esempio in cui vengono create le attività di lettura analogica e di lettura digitale. In questo modo, puoi realizzare progetti più avanzati utilizzando solo le API Arduino Uno e FreeRTOS.