
In questa settima lezione tratteremo delle metodologie per creare delle pause di ritardo. Il Raspberry Pi è estremamente veloce e, a volte, è necessario adattare le sue tempistiche a quelle dell'uomo. Le modalità per rallentare i tempi, in un programma, sono molteplici. Passiamo in rassegna alcuni di essi determinandone, anche, i pro e i contro.
Introduzione
Immaginiamo se un programma debba visualizzare dei risultati sul monitor alla velocità intrinseca della CPU e della scheda video: non usando gli opportuni rallentamenti l'utente vedrebbe passare i dati in maniera estremamente veloce e avrebbe solo la sensazione di un rapido scorrimento di numeri e lettere, senza poterne leggere i contenuti. Oppure ancora, se un software di domotica debba avviare il lampeggio di una lampada, collegata alle uscite digitali del Raspberry Pi: senza le tempistiche giuste, le lampade si accenderebbero e si spegnerebbero migliaia di volte in un secondo, senza poter essere controllate dagli utenti. Per fortuna esistono molti metodi che consentono, al software, di fermarsi un attimo e di dare modo, all'operatore, di prendere decisioni o d'interagire con i dispositivi collegati (vedi figura 1).

Figura 1: le pause di attesa sono estremamente importanti nei software, specialmente quelli interfacciati a circuiti elettronici
Il ciclo di loop a vuoto
Come si è appreso nel corso base di programmazione del linguaggio C su Raspberry Pi, si possono prevedere dei ritardi di esecuzione dei programmi usando, appunto, dei loop a vuoto. Essi non sono altro che dei semplici cicli iterativi (do, while, for) che si ripetono un elevato numero di volte, non eseguendo proprio nulla. Proprio come quando una persona percorre, camminando, l'area perimetrale di una stanza, senza portare a termine nessuna azione utile e pratica. Tale metodologia serve, appunto, a far perdere del tempo alla CPU. Un esempio di ciclo a vuoto potrebbe essere il seguente:
for(t=1;t<=30000000;t++);
Come si nota, il punto e virgola alla fine dello statement ne decreta subito la sua atomicità, e le istruzioni che a esso seguono, sono eseguite solo dopo che il ciclo stesso ha termine. Se vogliamo fare un altro esempio pratico, il loop a vuoto è paragonabile al conteggio che fanno i bambini giocando a nascondino: 1, 2, 3, 4, 5, 6, ecc. Essi prendono del tempo in attesa che i giocatori si nascondano bene in luoghi sicuri, per non essere scoperti. Prepariamo, allo scopo, un semplice esempio, che consente il lampeggio di un diodo Led collegato alla porta GPIO4 del Raspberry Pi, come si evince dalla figura 2.
Come si vede, è presente una resistenza di limitazione della corrente da 100 ohm, dal momento che le porte di I/O gestiscono la tensione di 3.3V. Realizziamo, adesso, un semplice software, in linguaggio C, che consenta il lampeggiamento del diodo Led a una determinata cadenza. Il listato è proposto qui sotto.
#define RITARDO 30000000 #include "stdio.h" int main() { FILE *handle; int k; long t; /*------Crea la porta GPIO4------*/ handle=fopen("/sys/class/gpio/export","w"); fprintf(handle,"4"); fclose(handle); /*-----Definisce la porta GPIO4 in uscita------*/ handle=fopen("/sys/class/gpio/gpio4/direction","w"); fprintf(handle,"out"); fclose(handle); for(k=1;k<=10;k++) { /*------Accende il diodo Led-----*/ handle=fopen("/sys/class/gpio/gpio4/value","w"); fprintf(handle,"1"); fclose(handle); /*----------Pausa di Ritardo--------*/ for(t=1;t<=RITARDO;t++); /*------------Spegne il diodo Led------*/ handle=fopen("/sys/class/gpio/gpio4/value","w"); fprintf(handle,"0"); fclose(handle); /*----------Pausa di Ritardo--------*/ for(t=1;t<=RITARDO;t++); } /*----Rilascia la porta GPIO4------*/ handle=fopen("/sys/class/gpio/unexport","w"); fprintf(handle,"4"); fclose(handle); return 0; }
Quello che a noi interessa è la pausa di ritardo che avviene tra l'accensione e lo spegnimento del diodo Led, grazie all'opera dello statement:
for(t=1;t<=RITARDO;t++);
Inoltre, RITARDO è definito come valore pari a 30000000 grazie all'uso dei comandi di preprocessore. Modificando tale valore, ma non eccedendo il limite imposto dalla variabile di tipo long (essa è, infatti, definita come long), è possibile cambiare la velocità del lampeggio.
Il settaggio e la gestione delle porte di output è stata ampiamente trattata nel relativo corso base, a cui vi rimandiamo per una rilettura.
Cosa fa, dunque, tale pausa di ritardo implementata con un loop a vuoto? Semplicemente la variabile "t" inizia a incrementare il proprio valore, partendo da 1 e terminando a 30000000, nell'esempio, perdendo del tempo.
Un altro esempio di loop a vuoto potrebbe essere il seguente:
do { i++ } while (i<3000000)
Tale metodo, seppur funzionante, è altamente dipendente dalla velocità della CPU. Se, infatti, venisse overcloccato il microprocessore, i tempi della pausa varierebbero di conseguenza, probabilmente in maniera proporzionale. Non utilizzate, dunque, tale metodo quando occorrono precise temporizzazioni o se si prevede una sostituzione dell'intera piattaforma del Raspberry Pi con un modello superiore.
La funzione sleep()
Per usare tale funzione occorre includere il file d'intestazione "unistd.h". Il parametro passato specifica il numero di secondi di attesa nella quale essa esplica la sua funzionalità. Come da manuale, la funzione sleep() sospende l'esecuzione del programma per uno specificato intervallo di tempo. La sua sintassi è la seguente:
unsigned sleep(unsigned seconds);
[...]
ATTENZIONE: quello che hai appena letto è solo un estratto, l'Articolo Tecnico completo è composto da ben 2255 parole ed è riservato agli ABBONATI. Con l'Abbonamento avrai anche accesso a tutti gli altri Articoli Tecnici che potrai leggere in formato PDF per un anno. ABBONATI ORA, è semplice e sicuro.

Nella maggior parte delle applicazioni, occorre rallentare l’esecuzione del programma per permettere all’operatore di prendere decisioni o per far si che gli eventi generati dalla macchina siano visibili anche all’uomo.
Ma esistono altri tipi di applicazioni dove, al contrario, è richiesta la MASSIMA velocità possibile. Quindi vengono eliminate tutte le pause e, anzi, sono ricercati metodi per velocizzare il più possibile il codice.
E’ il caso della ricerca dei numeri primi, dei classici algoritmi a forza bruta o AI, o del caso di deep search in alberi binari o simili. In questi casi, oltre all’algoritmo ottimizzato fa parte da leone anche la velocità della CPU, anche in un network di calcolo parallelo.
Un articolo molto dettagliato complimenti. Visto che parliamo di C avanzato io aggiungerei anche che le soluzioni come il for o il ciclo while sul clock sono vivamente sconsigliate (non solo perchè il for dipende dalla velocità del processore e quindi il codice è difficilmente portabile su piattaforme diverse) ma anche perchè implicano l’utilizzo del processore durante l’attesa semplicemente per effettuare operazioni a vuoto. Utilizzando invece le funzioni di librerie ottimizzate, si fa in modo che il processore sia disponibile anche per le altre applicazioni (soprattutto se lavoriamo con un sistema multi-thread).
Ottimo articolo. L’ambiente di sviluppo per il Raspberry Pi è molto versatile e mette a disposizione dello sviluppatore numerosi metodi per la gestione e misura del tempo.
Eh si. Grazie del commento.
In questi casi occorrerebbe calibrare il valore del loop in dipendenza della CPU, anche se, in effetti, la CPU “girerebbe” a vuoto.
Come sempre ottimo articolo.
Essendo più ferrato sulla programmazione della scheda Arduino, sono stato piacevolmente colpito dall’esempio con la libreria Wiring.pi più vicino alle mie conoscenze.
Articolo molto chiaro e approfondito. Il C è un linguaggio efficiente e viene utilizzato come riferimento per progettare software di sistema sulla maggior parte delle piattaforme hardware oggi in uso.
Grazie Giovanni, ho appena letto l’articolo e trovo interessante ed utile il modo in cui hai confrontato le varie funzioni sottolineandone l’utilizzo e la finalità più corretta. Soprattutto per i meno esperti è fondamentale avere indicazioni di questo tipo per poter procedere in autonomia oltre naturalmente agli aspetti più tecnici.
Grazie a tutti.
Si, ho descritto molti metodi per generare i ritardi, sia efficienti che non.
Esistono anche metodi che richiamano le API di Windows o particolari librerie, ma in questo caso il codice sarebbe molto meno portabile e dipendente dalle piattaforme o S.O.