- Cos'è il multitasking?
- Perché saltare delay () in Arduino?
- Perché usare millis ()?
- Componenti richiesti
- Schema elettrico
- Programmazione di Arduino UNO per il multitasking
Il multitasking ha portato i computer a una rivoluzione in cui uno o più programmi possono essere eseguiti contemporaneamente, aumentando l'efficienza, la flessibilità, l'adattabilità e la produttività. Nei sistemi embedded, i microcontrollori possono anche gestire il multitasking ed eseguire due o più attività contemporaneamente senza interrompere le istruzioni correnti.
Qui in questo tutorial impareremo come Arduino esegue il multitasking con la funzione Arduino millis. Generalmente una funzione delay () viene utilizzata in Arduino per un'attività periodica come LED lampeggiante, ma questa funzione delay () interrompe il programma per un certo tempo definitivo e non consente l'esecuzione di altre operazioni. Quindi questo articolo spiega come possiamo evitare l'uso della funzione delay () e sostituirla con millis () per eseguire più di un'attività contemporaneamente e rendere Arduino un controller multitasking. Prima di entrare nei dettagli, iniziamo con la minimizzazione del multitasking.
Cos'è il multitasking?
Multitasking significa semplicemente eseguire più di un'attività o programma contemporaneamente allo stesso tempo. Quasi tutti i sistemi operativi sono dotati di multitasking. Questo tipo di sistemi operativi sono noti come MOS (sistema operativo multitasking). Il MOS può essere un sistema operativo per PC mobile o desktop. Il buon esempio di multitasking nei computer è quando gli utenti eseguono l'applicazione di posta elettronica, il browser Internet, il lettore multimediale, i giochi, allo stesso tempo e se gli utenti non vogliono utilizzare l'applicazione viene eseguita in background se non chiusa. L'utente finale utilizza tutte queste applicazioni contemporaneamente, ma il sistema operativo prende questo concetto un po 'diverso. Parliamo di come il sistema operativo gestisce il multitasking.
Come si vede nella figura, la CPU divide il tempo in tre parti uguali e assegna ciascuna parte a ciascuna attività / applicazione. Questo è il modo in cui viene eseguito il multitasking nella maggior parte dei sistemi. Il concetto sarà quasi lo stesso per Arduino Multitasking, tranne che la distribuzione del tempo sarà leggermente diversa. Poiché Arduino funziona a bassa frequenza e la RAM è paragonabile a Laptop / Mobile / PC, anche il tempo assegnato a ciascuna attività sarà diverso. Arduino ha anche una funzione delay () ampiamente utilizzata. Ma prima di iniziare discutiamo del motivo per cui non dovremmo usare la funzione delay () in nessun progetto.
Perché saltare delay () in Arduino?
Se si considera la documentazione di riferimento di Arduino, esistono due tipi di funzioni di ritardo, la prima è delay () e la seconda è delayMicroseconds (). Entrambe le funzioni sono identiche in termini di generazione del ritardo. L'unica differenza è che, nella funzione delay (), il parametro intero passato è in millisecondi, cioè se scriviamo delay (1000) allora il ritardo sarà di 1000 millisecondi, cioè 1 secondo. Allo stesso modo nella funzione delayMicroseconds (), il parametro passato è in microsecondi, cioè se scriviamo delayMicroseconds (1000), allora il ritardo sarà di 1000 microsecondi cioè 1 millisecondi.
Ecco il punto, entrambe le funzioni mettono in pausa il programma per il tempo trascorso nella funzione di ritardo. Quindi, se stiamo fornendo un ritardo di 1 secondo, il processore non può passare all'istruzione successiva fino a quando non è trascorso 1 secondo. Allo stesso modo, se il ritardo è di 10 secondi, il programma si fermerà per 10 secondi e il processore non consentirà di eseguire le istruzioni successive fino a quando non saranno trascorsi i 10 secondi. Ciò ostacola le prestazioni del microcontrollore in termini di velocità e di esecuzione delle istruzioni.
Il miglior esempio per spiegare l' inconveniente della funzione di ritardo è l'utilizzo di due pulsanti. Considera di voler attivare due LED utilizzando due pulsanti. Quindi, se viene premuto un pulsante, il LED corrispondente dovrebbe accendersi per 2 secondi, allo stesso modo se viene premuto il secondo, il LED dovrebbe accendersi per 4 secondi. Ma quando usiamo delay (), se l'utente sta premendo il primo pulsante, il programma si fermerà per 2 secondi e se l'utente preme il secondo pulsante prima di 2 secondi di ritardo, il microcontrollore non accetterà l'input come il programma è in fase di arresto.
La documentazione ufficiale di Arduino lo menziona chiaramente nelle sue note e avvertenze di descrizione della funzione delay (). Puoi passare e controllare questo per renderlo più chiaro.
Perché usare millis ()?
Per superare il problema causato dall'uso del ritardo, uno sviluppatore dovrebbe utilizzare la funzione millis () che è facile da usare una volta diventato abituale e utilizzerà le prestazioni della CPU al 100% senza generare alcun ritardo nell'esecuzione delle istruzioni. millis () è una funzione che restituisce semplicemente la quantità di millisecondi trascorsi da quando la scheda Arduino ha iniziato a eseguire il programma corrente senza congelare il programma. Questo numero di tempo andrà in overflow (cioè tornerà a zero), dopo circa 50 giorni.
Proprio come Arduino ha delayMicroseconds (), ha anche la versione micro di millis () come micros (). La differenza tra micros e millis è che il micros () trabocca dopo circa 70 minuti, rispetto a millis () che è di 50 giorni. Quindi, a seconda dell'applicazione, puoi usare millis () o micros ().
Utilizzando millis () invece di delay ():
Per utilizzare millis () per la temporizzazione e il ritardo, è necessario registrare e memorizzare l'ora in cui è avvenuta l'azione per avviare l'ora e quindi controllare a intervalli se il tempo definito è trascorso. Quindi, come affermato, memorizza l'ora corrente in una variabile.
corrente lunga non firmataMillis = millis ();
Abbiamo bisogno di altre due variabili per scoprire se è trascorso il tempo richiesto. Abbiamo memorizzato l'ora corrente nella variabile currentMillis , ma dobbiamo anche sapere quando è iniziato il periodo di temporizzazione e quanto è lungo il periodo. Quindi vengono dichiarati Interval e precedente Millis. L'intervallo ci dirà il ritardo e previosMillis memorizzerà l'ultima volta che si è verificato l'evento.
unsigned long previousMillis; periodo lungo senza segno = 1000;
Per capirlo, facciamo un esempio di un semplice LED lampeggiante. Il periodo = 1000 ci dirà che il LED lampeggerà per 1 secondo o 1000 ms.
const int ledPin = 4; // il numero di pin del LED connesso int ledState = LOW; // utilizzato per impostare lo stato del LED unsigned long previousMillis = 0; // memorizzerà l'ultima volta che il LED ha lampeggiato cost long period = 1000; // periodo in cui lampeggiare in ms void setup () { pinMode (ledPin, OUTPUT); // imposta ledpin come output } void loop () { unsigned long currentMillis = millis (); // salva l' ora corrente if (currentMillis - previousMillis> = period) {// controlla se 1000 ms sono passati previousMillis = currentMillis; // salva l'ultima volta che hai fatto lampeggiare il led if (ledState == LOW) {// se il led è spento accendilo e viceversa ledState = HIGH; } altro { ledState = LOW; } digitalWrite (ledPin, ledState); // imposta il LED con ledState per lampeggiare di nuovo } }
Ecco la dichiarazione
Gli interrupt in Arduino funzionano come in altri microcontrollori. La scheda Arduino UNO ha due pin separati per il collegamento degli interrupt sui pin GPIO 2 e 3. Lo abbiamo trattato in dettaglio nel Tutorial sugli interrupt di Arduino, dove puoi imparare di più sugli interrupt e su come usarli.
Qui mostreremo Arduino Multitasking gestendo due attività contemporaneamente. Le attività includeranno il lampeggiamento di due LED con un ritardo di tempo diverso insieme a un pulsante che verrà utilizzato per controllare lo stato ON / OFF del LED. Quindi tre attività verranno eseguite contemporaneamente.
Componenti richiesti
- Arduino UNO
- Tre LED (qualsiasi colore)
- Resistenze (470, 10k)
- Ponticelli
- Breadboard
Schema elettrico
Lo schema del circuito per dimostrare l'uso della funzione Arduino Millis () è molto semplice e non ha molti componenti da collegare come mostrato di seguito.
Programmazione di Arduino UNO per il multitasking
La programmazione di Arduino UNO per il multitasking richiederà solo la logica alla base del funzionamento di millis (), spiegata sopra. Si consiglia di esercitarsi a lampeggiare il LED usando millis ancora e ancora per rendere chiara la logica e mettersi a proprio agio con millis () prima di iniziare a programmare Arduino UNO per il multitasking. In questo tutorial l'interrupt viene utilizzato anche con millis () contemporaneamente per il multitasking. Il pulsante sarà un'interruzione. Pertanto, ogni volta che viene generato un interrupt, ovvero viene premuto il pulsante, il LED passa allo stato ON o OFF.La programmazione inizia con la dichiarazione dei numeri dei pin a cui sono collegati i LED e il pulsante.
int led1 = 6; int led2 = 7; int toggleLed = 5; int pushButton = 2;
Successivamente scriviamo una variabile per memorizzare lo stato dei LED per un utilizzo futuro.
int ledState1 = LOW; int ledState2 = LOW;
Proprio come spiegato sopra nell'esempio lampeggiante, le variabili per periodo e millis precedenti vengono dichiarate per confrontare e generare ritardo per i LED. Il primo LED lampeggia dopo ogni secondo e un altro LED lampeggia dopo 200 ms.
unsigned long previousMillis1 = 0; const lungo periodo1 = 1000; unsigned long previousMillis2 = 0; const lungo periodo2 = 200;
Un'altra funzione millis verrà utilizzata per generare il ritardo di antirimbalzo per evitare le pressioni multiple del pulsante. Ci sarà un approccio simile come sopra.
int debouncePeriod = 20; int debounceMillis = 0;
Le tre variabili verranno utilizzate per memorizzare lo stato del pulsante come interruzione, LED di commutazione e stato del pulsante.
bool buttonPushed = false; int ledChange = LOW; int lastState = HIGH;
Definisci l'azione del pin che quale pin funzionerà come INPUT o OUTPUT.
pinMode (led1, OUTPUT); pinMode (led2, OUTPUT); pinMode (toggleLed, OUTPUT); pinMode (pushButton, INPUT);
Ora definisci il pin di interrupt allegando l'interrupt con la definizione di ISR e la modalità di interrupt. Si noti che si consiglia di utilizzare digitalPinToInterrupt (pin_number) quando si dichiara la funzione attachInterrupt () per tradurre il pin digitale effettivo nel numero di interrupt specifico.
attachInterrupt (digitalPinToInterrupt (pushButton), pushButton_ISR, CHANGE);
La subroutine di interrupt viene scritta e cambierà solo il flag buttonPushed. Si noti che la subroutine di interrupt dovrebbe essere la più breve possibile, quindi provare a scriverla e ridurre al minimo le istruzioni aggiuntive.
void pushButton_ISR () { buttonPushed = true; }
Il ciclo inizia con la memorizzazione del valore in millisecondi in una variabile currentMillis che memorizzerà il valore del tempo trascorso ogni volta che il ciclo itera.
corrente lunga non firmataMillis = millis ();
Ci sono in totale tre funzioni nel multitasking, lampeggia un LED a 1 secondo, lampeggia il secondo LED a 200 ms e se viene premuto il pulsante, spegni / accende il LED. Quindi scriveremo tre parti per svolgere questo compito.
Il primo alterna lo stato del LED ogni 1 secondo confrontando i millisecondi.
if (currentMillis - previousMillis1> = period1) { previousMillis1 = currentMillis; if (ledState1 == LOW) { ledState1 = HIGH; } else { ledState1 = LOW; } digitalWrite (led1, ledState1); }
Allo stesso modo in secondo luogo attiva il LED ogni 200 ms confrontando i millisecondi trascorsi. La spiegazione è già spiegata in precedenza in questo articolo.
if (currentMillis - previousMillis2> = period2) { previousMillis2 = currentMillis; if (ledState2 == LOW) { ledState2 = HIGH; } else { ledState2 = LOW; } digitalWrite (led2, ledState2); }
Infine, il flag buttonPushed viene monitorato e dopo aver generato un ritardo di antirimbalzo di 20ms commuta solo lo stato del LED corrispondente al pulsante collegato come interrupt.
if (buttonPushed = true) // controlla se ISR è chiamato { if ((currentMillis - debounceMillis)> debouncePeriod && buttonPushed) // genera un ritardo di debounce di 20ms per evitare pressioni multiple { debounceMillis = currentMillis; // salva l'ultimo tempo di ritardo antirimbalzo if (digitalRead (pushButton) == LOW && lastState == HIGH) // cambia il led dopo aver premuto il pulsante { ledChange =! ledChange; digitalWrite (toggleLed, ledChange); lastState = LOW; } else if (digitalRead (pushButton) == HIGH && lastState == LOW) { lastState = HIGH; } buttonPushed = false; } }
Questo termina il tutorial di Arduino millis (). Nota che per diventare abituale con millis (), fai pratica per implementare questa logica in alcune altre applicazioni. Puoi anche ampliarlo per utilizzare motori, servomotori, sensori e altre periferiche. In caso di dubbio scrivi al nostro forum o commenta qui sotto.
Di seguito vengono forniti il codice completo e il video per dimostrare l'uso della funzione millis in Arduino.