Spesso appare la domanda “come faccio per eseguire più compiti simultaneamente ?”, la risposta è sempre la stessa, Arduino non ha un processore multicore pertanto può fare solo una cosa per volta, però dato che la fa molto velocemente si può ottenere “l’illusione” di farne diverse assieme.
Solitamente viene consigliato di utilizzare la millis() per gestire i tempi di esecuzione, va bene però è un sistema poco pratico e confusionario.
Esiste una soluzione migliore ed è quella di realizzare un RTOS molto minimale che garantisce, entro certi limiti, di poter eseguire dei compiti (task) a determinati intervalli determinato in modo abbastanza preciso.
Quanto sto per andare ad illustrare è proprio come realizzare un semplice RTOS per Arduino, l’ho definito quasi RTOS perché implementa solo la possibilità di lanciare dei task a intervalli predeterminati, un vero RTOS fa molte più cose
Il funzionamento di qRTOS è basato sull’utilizzo del timer del watchdog, esattamente come fa il LeOS2 di Leo72, però c’è una sostanziale differenza, prima di tutto il mio qRTOS non è una libreria come normalmente viene intesa su Arduino, sono una ISR e delle funzioni pronte all’uso mirate a questo specifico scopo, scritte in modo ottimale per minimizzare l’impatto sul tempo cpu e l’uso minimale delle risorse, inoltre, a differenza di quanto avviene nel LeOS2, i task sono eseguiti all’esterno della ISR del watchdog, sono interrompibili da eventuali interrupt, non bloccano l’esecuzione di altri eventuali processi richiamati da interrupt.
Nel file allegato trovate uno sketch di esempio che fa lampeggiare il led sul pin 13 ogni 160ms, invia due stringhe sulla seriale, una ogni 960ms e una ogni 1920ms, il tutto senza codice all’interno della loop
In pratica la loop è fatta in questo modo:
void loop()
{
Sequencer();
}
Tutto il lavoro lo fa la funzione “Sequencer()”, è uno semplice scheduler che gestisce i processi in coda in base ai timing assegnati ai task.
Il “trucco” sta nella ISR del watchdog:
//ISR watchdog
ISR(WDT_vect, ISR_NOBLOCK)
{
// incrementa contatori
Count_Task1++;
Count_Task2++;
Count_Task3++;
Count_Task4++;
Count_Task5++;
Count_Task6++;
// verifica timeout
// Task 1
if (Count_Task1 >= Time_Task1)
{
Count_Task1 = 0;
Flag_Task1 = HIGH;
}
................
}
Questa ISR non fa altro che incrementare le variabili Count_Taskn ogni 16 ms, overflow del timer watchdog, e se uno dei contatori raggiunge il valore definito in “Time_Taskn” setta il flag “Flag_Task1”.
La funzione “Sequencer”, invocata continuamente nella loop, non fa altro che verificare quali flag sono HIGH, li resetta e lancia la funzione abbinata, nell’esempio sono denominate myTaskn però potete mettere i nomi che preferiti.
L’esempio prevede fino a sei diversi task, non dovete necessariamente utilizzarli tutti, potete aumentarli a piacere, entro i limiti operativi del micro, semplicemente facendo copia e incolla delle varie porzioni della ISR e di Sequencer cambiando i relativi nomi.
qRTOS.zip (1.7 KB)