Arduino: strutturare il codice in blocchi funzionali

Molto spesso durante le prime fasi di realizzazione di uno sketch Arduino si tende a non strutturare il proprio programma in blocchi funzionali separati, tutto il codice viene inserito all’interno del loop(). Questo tipo di approccio, soprattutto se siamo in presenza di un codice molto lungo, rende difficoltosa la lettura del programma da parte di altre persone e non permette una facile comprensione del funzionamento o l’identificazione di possibili errori.

Ho parlato in passato come strutturare il codice in blocchi funzionali nel post:
Arduino – lezione 07: lavorare con gruppi di valori e funzioni esterne, ma in quella lezione utilizzavo istruzioni che in questa fase dell’anno scolastico non sono ancora conosciute da alcuni allievi soprattutto del 3′ anno, che iniziano ad utilizzare Arduino, pertanto la presente lezione dovrebbe chiarire in modo più semplice l’argomento.

Le funzioni vengono utilizzate per organizzare le azioni eseguite dal vostro programma. Ogni funzione può essere identificata da un’azione specifica richiamata dal programma principale loop(), oppure richiamate da altre funzioni sempre all’interno del nostro sketch.

Senza saperlo quando avete iniziato a programmare con Arduino avete utilizzato delle funzioni: loop() e setup() le due funzioni sempre presenti in ogni sketch.

Per creare una funzione bisogna:

  • definire il tipo di valore restituito dalla funzione;
  • assegnare un nome alla funzione;
  • e opzionalmente impostare una serie di parametri che la funzione riceverà quando viene chiamata (si dice anche invocata).

Creiamo una semplice funzione che permette di fare lampeggiare un LED, non possiede parametri e non restituisce nessun valore.
Assegnare alla funzione il tipo void vuol dire che non restituisce nulla e non inserire nulla tra le parentesi tonde indica che la funzione non accetta nessun parametro.

Esempio 1

1// Prof. Michele Maffucci
2// Es.01 - Usare le funzioni
3// Data: 15.11.2020
4 
5void setup() {
6  pinMode(LED_BUILTIN, OUTPUT);
7}
8 
9void loop() {
10  lampeggia();
11}
12 
13// blink LED una volta
14void lampeggia()
15{
16  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
17  delay(1000); // pausa di 1 secondo
18  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
19  delay(1000); // pausa di 1 secondo
20}

Ogni volta che il loop() chiama (invoca) la funzione esterna lampeggia() viene effettuato il blink del LED sulla scheda.

Esempio 2

Realizziamo ora un secondo esempio in cui la funzione “lampeggia” accetta come parametro un valore intero che definisce il delay da impostare all’interno del funzione.

1// Prof. Michele Maffucci
2// Es.02 - Usare le funzioni
3// Data: 15.11.2020
4 
5void setup() {
6  pinMode(LED_BUILTIN, OUTPUT);
7}
8 
9void loop() {
10  // chiamiamo la funzione lampeggia passando il valore
11  // specificato all'interno delle parentesi tonde
12  lampeggia(250);
13}
14 
15// blink LED una volta
16// per far si che la funzione accetti un parametro in input
17// bisogna dichiarare il tipo del parametro in ingresso
18// nella funzione lampeggia: int pausa
19 
20void lampeggia(int pausa)
21{
22  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
23  delay(pausa); // pausa: valore inserito nella variabile "pausa"
24  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
25  delay(pausa); // pausa: valore inserito nella variabile "pausa"
26}

Esempio 3

Realizziamo ora un terzo sketch in cui i parametri di ingresso per la funzione lampeggia() sono due, uno che definisce il tempo di accensione del LED ed uno che definisce il tempo di spegnimento del LED:

1// Prof. Michele Maffucci
2// Es.03 - Usare le funzioni
3// Data: 15.11.2020
4 
5void setup() {
6  pinMode(LED_BUILTIN, OUTPUT);
7}
8 
9void loop() {
10  // chiamiamo la funzione lampeggia passando il valore
11  // specificato all'interno delle parentesi tonde
12  lampeggia(250, 1000);
13}
14 
15// blink LED una volta
16// per far si che la funzione accetti duen parametri in input
17// bisogna dichiarare il tipo per ogni parametro in ingresso
18// nella funzione lampeggia: int pausaOn e int pausaOff
19 
20void lampeggia(int pausaOn, int pausaOff)
21{
22  digitalWrite(LED_BUILTIN, HIGH); // accende il LED
23  delay(pausaOn); // delay LED ON
24  digitalWrite(LED_BUILTIN, LOW); // spegne il LED
25  delay(pausaOff); // delay LED OFF
26}

Esempio 4

Definiamo ora una funzione che ha 3 parametri di ingresso: il tempo in cui il LED rimane acceso, il tempo in cui il LED rimane spento e il numero di volte (cicli) che deve ripetersi il lampeggio, al termine del numero di cicli il LED non lampeggerà più. Come specificato nei commenti la variabile chiave verrà utilizzata per eseguire una volta sola la chiamata della funzione lampeggio:

1// Prof. Michele Maffucci
2// Es.04 - Usare le funzioni
3// Data: 15.11.2020
4 
5// chiave e la variabile che consente l'esecuzione della
6// chiamata della funzione lampegga una sola volta
7int chiave = 0;
8 
9void setup() {
10  pinMode(LED_BUILTIN, OUTPUT);
11}
12 
13void loop() {
14  // chiamiamo la funzione lampeggia passando il valore
15  // specificato all'interno delle parentesi tonde
16  if (chiave == 0) {
17    chiave = 1;
18    lampeggia(250, 1000, 5);
19  }
20}
21 
22// blink LED una volta
23// per far si che la funzione accetti tre parametri in input
24// bisogna dichiarare il tipo per ogni parametro in ingresso
25// nella funzione lampeggia: int pausaOn, int pausaOff, int contatore
26// la variabile contatore definisce il numero di cicli di lampeggio
27 
28void lampeggia(int pausaOn, int pausaOff, int contatore)
29{
30  for (int i = 0; i < contatore; i++) {
31    digitalWrite(LED_BUILTIN, HIGH); // accende il LED
32    delay(pausaOn); // delay LED ON
33    digitalWrite(LED_BUILTIN, LOW); // spegne il LED
34    delay(pausaOff); // delay LED OFF
35  }
36}

All’interno dello sketch precedente la funzione lampeggio utilizza un ciclo for per ripetere, per il numero di volte specificato dalla variabile contatore, il codice di accensione e spegnimento (corpo del for).

Esempio 5

Per completezza e per richiamare il modo con cui utilizzare l’istruzione while, di seguito trovate lo sketch che realizza la medesima funzionalità dello sketch precedente in cui il ciclo for viene sostituito da un while:

1// Prof. Michele Maffucci
2// Es.05 - Usare le funzioni
3// Data: 15.11.2020
4 
5// chiave e la variabile che consente l'esecuzione della
6// chiamata della funzione lampegga una sola volta
7int chiave = 0;
8 
9void setup() {
10  pinMode(LED_BUILTIN, OUTPUT);
11}
12 
13void loop() {
14  // chiamiamo la funzione lampeggia passando il valore
15  // specificato all'interno delle parentesi tonde
16  if (chiave == 0) {
17    chiave = 1;
18    lampeggia(250, 1000, 5);
19  }
20}
21 
22// blink LED una volta
23// per far si che la funzione accetti tre parametri in input
24// bisogna dichiarare il tipo per ogni parametro in ingresso
25// nella funzione lampeggia: int pausaOn, int pausaOff, int contatore
26// la variabile contatore definisce il numero di cicli di lampeggio
27 
28void lampeggia(int pausaOn, int pausaOff, int contatore)
29{
30  while (contatore > 0) {
31     digitalWrite(LED_BUILTIN, HIGH); // accende il LED
32    delay(pausaOn); // delay LED ON
33    digitalWrite(LED_BUILTIN, LOW); // spegne il LED
34    delay(pausaOff); // delay LED OFF
35    contatore = contatore - 1; // decremento del contatore
36  }
37}

Esempio 6

Nello sketch che segue realizziamo una funzione che accetta un parametro e restituisce un valore. Il parametro che viene passato alla funzione definisce la durata dei tempi di accensione e spegnimento del LED (in millisecondi). La funzione continua a far lampeggiare un LED fino a quando non viene premuto un pulsante. Il valore restituito dalla funzione è il numero di lampeggi effettuati, questo valore verrà stampato sulla Serial Monitor:

1// Prof. Michele Maffucci
2// Es.06 - Usare le funzioni
3// Data: 15.11.2020
4 
5const int pinPulsante = 8; // pin a cui colleghiamo il pulsante
6 
7void setup() {
8  pinMode(LED_BUILTIN, OUTPUT);
9  pinMode(pinPulsante, INPUT);
10  Serial.begin(9600);
11}
12 
13void loop() {
14  Serial.println("Premere il pulsante per interrompere il lampeggio");
15  int contatore = lampeggia(500); // lampeggio del LED: 500 ms ON e 500 ms OFF
16  Serial.print("Il numero di volte in cui il LED ha lampeggiato è stato di: ");
17  Serial.println(contatore);
18  while (digitalRead(pinPulsante) == HIGH)
19  {
20    // non viene fatto nulla fino a quando non rilascio il pulsante
21  }
22}
23 
24// la funzione fa lampeggiare il LED per un periodo specificato (int periodo)
25// e restituisce il numero di volte in cui il LED ha lampeggiato
26 
27int lampeggia(int periodo)
28{
29  int contatoreLampeggio = 0;
30 
31  while (digitalRead(pinPulsante) == LOW)
32    // ripetere finché non viene premuto il pulsante
33    // cicla fino a quando il pulsante non viene premuto
34  {
35    digitalWrite(LED_BUILTIN, HIGH);
36    delay(periodo);
37    digitalWrite(LED_BUILTIN, LOW);
38    delay(periodo);
39    contatoreLampeggio = contatoreLampeggio + 1; // incrementa il contatore
40  }
41  // in questo punto vuol dire che pinPulsante è HIGH
42  // ciò vuol dire che il pulsante è premuto
43 
44  // contatoreLampeggio è il valore che viene restituito alla funzione chiamante
45  return contatoreLampeggio;
46}

Il tipo di dato che precede in nome della funzione:

int lampeggia()

indica il tipo di dato restituito dalla funzione. Ricordarsi che nella funzione chiamante, nel nostro caso il loop(), quando chiamiamo la funzione questa deve terminare con un punto e virgola:

1int contatore = lampeggia(500);

Errori comuni che vengono commessi nella chiamata di funzioni

Rimando a queste due brevi note che mostrano alcuni errori tipici:

Buon Making a tutti 🙂

Esercizi per i miei studenti

Esercizio 1

Realizzare un circuito costituito da 4 pulsanti e 4 led, connessi ad Arduino.

  • Alla pressione del pulsante P1 il LED1 effettua il blink con un tempo di 200 ms
  • Alla pressione del pulsante P2 il LED2 effettua il blink con un tempo di 400 ms
  • Alla pressione del pulsante P3 il LED3 effettua il blink con un tempo di 600 ms
  • Alla pressione del pulsante P4 il LED4 effettua il blink con un tempo di 800 ms

Fare in modo tale che ci sia una funzione esterna, chiamata dal loop(), che effettui il blink dei led.

Esercizio 2

Aggiungere all’esercizio 1 un pulsante che se premuto accende in sequenza ripetuta i 4 led. L’accensione in sequenza deve avvenire chiamando una funzione esterna al loop().

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.