Archivi tag: array

Arduino – Trovare il valore più grande in un array

Durante queste settimane inevitabilmente le attività di PCTO vengono svolte in parte in presenza ed in parte in remoto. Le lezioni in remoto vengono ovviamente utilizzate per risolvere dubbi e spiegare qualcosa di nuovo che possa essere di aiuto ai ragazzi. Ultimamente alcuni mie studenti di classe 3′ sono impegnati chi nella realizzazione di serre idroponiche e chi nel simulare il funzionamento di un’incubatrice neonatale, in entrambe le situazioni bisogna rilavare grandezze fisiche, come ad esempio la temperatura. Spesso è necessario leggere dai sensori in un determinato intervallo di tempo una sequenza di valori che dovranno essere memorizzati in un array e successivamente elaborati.

Come detto sopra, è spesso utile memorizzare una sequenza di numeri, ad esempio una sequenza di letture di temperatura, all’interno di un array e poi dalla lista estrarre il valore che ci interessa, ad esempio: la massima temperatura, la minima temperatura, la media, ecc…

Per fare questa operazione il metodo più semplice ed intuitivo consiste nello leggere la sequenza dei valori per cercare il più grande.

Ma come costruire un algoritmo per fare questa operazione?

Riprendo un esempio che facevo tempo fa ai ragazzi declinato da alcune spiegazioni di un vecchio libro di informatica su cui studiai io 🙂

Immaginate la seguente situazione:

il mio collega con cui lavoro in compresenza, che chiamerò Prof. Rossi, mi detta la lista dei voti assegnati ad uno di voi, non mi dice in anticipo quanti voti mi detterà, me li detta ed io devo costruire un algoritmo che mi permetterà di dire al collega qual è il voto più altro nel momento in cui mi dirà:

“basta non ci sono più voti!”,

istantaneamente, senza rileggere tutta la lista devo fornire questa informazione al collega.

Partiamo!

  • Il primo voto che mi viene dettato è “3.5”, allora lo scriverò su un foglio di carta;
  • il secondo voto è 6.75 che è più grande di 3 quindi potrebbe essere questo il massimo dei voti, cancello 3.5 e scrivo sulla pagina il 6.75;
  • subito dopo mi viene detto: “5.5” che è più piccolo di 6.75 quindi non potrà essere questo il voto più alto, lasceremo scritto sul foglio 6.75;
  • mi viene detto: “9” ed essendo più grande di 6.75 lo indico sul mio foglio, cancellando il 6.75;
  • il voto successivo è 7.25, che è inferiore al 9 e non lo riporto sul foglio;
  • il voto successivo è 8.75, che è inferiore al 9 e non lo riporto sul foglio;
  • Il Prof. Rossi mi avvisa che ha finito di dettarmi i voti ed io dirò immmediatamente che il voto massimo è 9;

Come possiamo tradurre in C questo algoritmo?

Realizziamo un Array in cui inserire la sequenza dei 6 voti:

sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};

Il passo successivo sarà quello di definire un contenitore (una variabile) in cui di volta in volta andremo a memorizzare il numero più grande che abbiamo trovato.

Definisco quindi “votoMassimo” la variabile che contiene il voto massimo temporaneo (quello che nell’esempio mi veniva dettato dal Prof. Rossi)

float votoMassimo = 0;

Sarà necessario utilizzare un ciclo for per leggere uno alla volta i voti della lista.

Il ciclo parte con indice 0 arrivando fino alla fine dell’array, cioè con indice pari a n-1 (n: dimensione dell’array), quindi l’array è costituito da n oggetti e l’indice che identifica la posizione va da 0 a n-1.

In C è possibile calcolare automaticamente la dimensione dell’array con la funzione: sizeof di cui trovate tutte le informazioni sul references di Arduino

sizeof(sequenzaVoti)/sizeof(float))

mi darà la dimensione n dell’array.

Approfondiamo quanto detto.

sizeof permette di ottenere la dimensione in byte di una variabile di qualsiasi tipo (int, float, byte, char, ecc…) o del numero di byte che occupa un array.

Attenzione però per definire un array possiamo farlo in due modi:

modo 1, indicando la dimensione tra parentesi quadre
float sequenzaVoti[6]

modo 2, enumerando gli elementi, nel nostro caso i voti, ovvero l’elenco degli oggetti
float sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};

Per sapere la dimensione in byte dell’array useremo sizeof() che restituirà la dimensione dell’array in byte.

Quindi l’operatore sizeof(sequenzaVoti) non restituirà il numero di celle dell’array, ma la sua dimensioni in byte, pertanto:

sizeof(sequenzaVoti)

restituirà come valore: 24 perchè l’array sequenzaVoti[] è costituita da 6 numeri reali (con la virgola), ciascuno di esso rappresentato da quattro byte pertanto il numero totale di byte dell’array è 6×4=24.

Per calcolare la dimensione dell’array, partendo dalla dimensione in byte ricavata da sizeof(), possiamo operare in questo modo:

1for (int i = 0; i < (sizeof(sequenzaVoti)/sizeof(float)); i++) {
2//codice…
3}

Per trovare il voto massimo bisogna verificare ad ogni ciclo del for se il valore attuale (sequenzaVoti[i]) risulta maggiore del valore che abbiamo memorizzato all’interno della variabile votoMassimo, per fare questo controllo utilizzeremo l’istruzione if:

1if (sequenzaVoti[i] > votoMassimo) {
2   // salviamo il valore massimo attuale...
3}

Se la condizione dell’if è verificata, bisogna sovrascriviamo il valore di “votoMassimo” con quello trovato della sequenza dei voti che stiamo leggendo.

votoMassimo = sequenzaVoti[i];

Detto ciò costruiamo lo sketch che, data una lista di 6 voti memorizzati in un array, stampa sulla serial monitor

Il voto massimo è:…

al posto dei puntini dovete stampare il voto massimo tra quelli scritti nell’array.
La lista dei voti, per ora, viene inserita nel codice, non dovrà essere scritta da computer sulla serial monitor.

Potete far eseguire tutto il codice di estrazione del voto massimo nel setup() con il loop() vuoto.

Per completezza con quanto spiegato, aggiungo alla stampa del voto massimo la stampa della dimensione massima dell’array sequenzaVoti[]

Il listato completo sarà:

1/*
2 * Prof. Michele Maffucci
3 * data 15.03.2021
4 *
5 * Trovare il valore più grande in un array
6 *
7 */
8 
9// sequenza di 6 voti di uno studente
10float sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};
11 
12void setup() {
13  Serial.begin(9600);
14 
15  // la variabile con il numero massimo:
16 
17  int votoMassimo = 0;
18 
19  for (int i = 0; i < (sizeof(sequenzaVoti) / sizeof(float)); i++) {
20    if (sequenzaVoti[i] > votoMassimo) {
21      // se il voto corrente è maggiore di quello
22      // salvato dentro votoMassimo allora lo copio 
23      votoMassimo = sequenzaVoti[i];
24    }
25  }
26  Serial.print("Il voto massimo è: ");
27  Serial.println(votoMassimo);
28  Serial.print("Dimensione in byte dell'array ");
29  Serial.println(sizeof(sequenzaVoti)); 
30}
31 
32void loop() {}

Esercizio 1
Realizzare uno sketch che accetta l’imputo dei voti (float) da tastiera e restituisce il voto massimo.

Esercizio 2
Realizzare uno sketch che accetta l’imputo dei voti (float) da tastiera e restituisce la media dei voti.

Buon Coding a tutti 🙂

Arduino: controllo sequenziale uscite digitali

Durante la progettazione di un sistema di automazione accade frequentemente di avere la necessità di ripetere, sequenzialmente e in modo continuo, l’attivazione di apparati (ad es. motori) oppure la lettura continua dei dati provenienti da più sensori. Come attività di ripasso per i miei studenti ho deciso di riprendere alcuni argomenti affrontati nelle scorse settimane con specifiche esperienze di laboratorio:

  • automi a stati finiti;
  • utilizzo degli array;
  • input valori interi da serial monitor;
  • marcia, arresto, pausa di sequenze;
  • controllo uscite digitali mediante ingressi analogici;
  • realizzazione di commutatori con pulsanti con uno o più pulsanti;
  • utilizzo corretto dei tipi di dati per risparmiare memoria;
  • e molto altro

Di seguito 9 sketch in cui vengono ripresi gli argomenti sopra elencati e che potranno essere utilizzati nei prossimi mesi per sviluppare ulteriori sperimentazioni.
Come sempre all’interno degli sketch proposti trovate le spiegazioni di ogni parte del codice ed in alcuni casi trovate link di approfondimento che rimandano a questo sito.

Per ripercorrere gli argomenti svolti partirò dal classico sketch che permette di realizza l’accensione sequenziale di LED, come quello che potete trovare nelle mie slice: Alfabeto Arduino – Lezione 2 a pagina 66.
I LED nel circuito identificano gli apparati da attivare sequenzialmente, realizzando così il classico effetto “super car” (i diversamente giovani 🙂 sanno perché si chiama così).
Circuito e sketch verranno poi modificati per rispondere alle specifiche indicate ad inizio di ogni esempio.

Sketch 01

Sequenza di accensione e spegnimento da destra e sinistra e viceversa di 8 LED con tempo di accensione di 100 millisecondi.

 

1/* Prof. Michele Maffucci
2   30.12.2020
3   Lezione di riferimento: https://wp.me/p4kwmk-4D3
4 
5   Versione 01
6   Sequenza di accensione e spegnimento alternato
7   da destra e sinistra e viceversa di 8 LED con
8   tempo di accensione di 100 millisecondi.
9    
10   Questo codice è di dominio pubblico
11 */
12 
13// creazione di un array di 8 pin a cui vanno collegati i LED
14// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
16 
17byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};
18 
19// per approfondimenti sull'uso dei tipi di dati
20// si consultino i link:
23 
24// intervallo di accensione/spegnimento
25byte ritardoLed = 100;
26 
27// indicatore di direzione di accensione
28byte direzione = 1;
29 
30// indice dell'array per l'accensione del LED
31byte ledCorrente = 0;
32 
33// variabile in cui memorizzare il tempo di accensione di Arduino
34// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
36 
37unsigned long tempoTrascorso;
38 
39void setup() {               
40  // impostiamo tutti i pin ad output
41  for (byte x=0; x<8; x++) {
42    pinMode(ledPin[x], OUTPUT);
43  }
44     
45  // Memorizzazione del tempo trascorso
46  // dal momento in cui avviamo Arduino
47  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
49   
50  tempoTrascorso = millis();
51}
52 
53void loop() {
54  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
55  if ((millis() - tempoTrascorso) > ritardoLed) {
56    cambiaStatoLed();
57    tempoTrascorso = millis();
58  }
59}
60 
61// la funzione cambiaStatoLed() permette di controllare
62// la sequenza di accensione dei LED
63 
64void cambiaStatoLed() {
65  // spegne tutti i LED
66  for (byte x=0; x<8; x++) {
67    digitalWrite(ledPin[x], LOW);
68  }
69  // accende il LED corrente
70  digitalWrite(ledPin[ledCorrente], HIGH);
71  // incrementa la variabile direzione
72  ledCorrente += direzione;
73  // cambia la direzione se si arriva alla fine
74  if (ledCorrente == 7) {
75    direzione = -1;
76  }
77  if (ledCorrente == 0) {
78    direzione = 1;
79  }
80}

Sketch 02

Sequenza di accensione e spegnimento da destra e sinistra e viceversa di 8 LED. Con un trimmer è possibile variare il tempo di accensione nell’intervallo da 50 millisecondi a 1000 millisecondi (1 secondo).

1/* Prof. Michele Maffucci
2   30.12.2020
3   Lezione di riferimento: https://wp.me/p4kwmk-4D3
4 
5   Versione 02
6   Sequenza di accensione e spegnimento alternato
7   da destra e sinistra e viceversa di 8 LED controllato
8   da un trimmer che permetterà di variare il tempo di accensione
9   da 50 millisecondi a 1000 millisecondi (1 secondo).
10    
11   Questo codice è di dominio pubblico
12 */
13 
14// creazione di un array di 8 pin a cui vanno collegati i LED
15// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
17 
18byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};
19 
20// per approfondimenti sull'uso dei tipi di dati
21// si consultino i link:
24 
25// intervallo di accensione/spegnimento
26int ritardoLed;
27 
28// variabile in cui memorizzare il valore restituito dall'analogRead
29int val = 0;
30 
31// indicatore di direzione di accensione
32byte direzione = 1;
33 
34// indice dell'array per l'accensione del LED
35byte ledCorrente = 0;
36 
37// variabile in cui memorizzare il tempo di accensione di Arduino
38// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
40 
41unsigned long tempoTrascorso;
42 
43void setup() {
44  Serial.begin(9600);           
45  // impostiamo tutti i pin ad output
46  for (byte x=0; x<8; x++) {
47    pinMode(ledPin[x], OUTPUT);
48  }
49     
50  // Memorizzazione del tempo trascorso
51  // dal momento in cui avviamo Arduino
52  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
54   
55  tempoTrascorso = millis();
56}
57 
58void loop() {
59 
60  // valore analogico letto su A0 inserito con il trimmer
61  val = analogRead(A0);
62 
63// Togliere il commento per valutare
64// valore massimo/minimo del valore restituito
65// dall'analogRead in questo modo si potranno
66// inserire nella map i valori massimi e minimi
67// dell'intervallo di partenza
68 
69// Serial.println(val);
70// delay(1000);
71 
72  // ValMax = 285, ValMin = 719
73  // riconvertiti nell'intervallo 50, 1000
74   
75  ritardoLed = map(val, 285, 719, 50, 1000);
76   
77  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
78  if ((millis() - tempoTrascorso) > ritardoLed) {
79    cambiaStatoLed();
80    tempoTrascorso = millis();
81  }
82}
83 
84// la funzione cambiaStatoLed() permette di controllare
85// la sequenza di accensione dei LED
86 
87void cambiaStatoLed() {
88  // spegne tutti i LED
89  for (byte x=0; x<8; x++) {
90    digitalWrite(ledPin[x], LOW);
91  }
92  // accende il LED corrente
93  digitalWrite(ledPin[ledCorrente], HIGH);
94  // incrementa la variabile direzione
95  ledCorrente += direzione;
96  // cambia la direzione se si arriva alla fine
97  if (ledCorrente == 7) {
98    direzione = -1;
99  }
100  if (ledCorrente == 0) {
101    direzione = 1;
102  }
103}

Sketch 03

Sequenza di accensione e spegnimento alternato da destra e sinistra e viceversa di 8 LED. L’accensione di ogni LED è fissato in partenza a 100 millisecondi. Con un messaggio sulle Serial Monitor viene richiesto di inserire un nuovo tempo di accensione e spegnimento di ogni LED (delay), tempo che può essere scelto a piacimento.

Lo schema di collegamento è analogo a quello utilizzato per lo sketch 01.

1/* Prof. Michele Maffucci
2   30.12.2020
3   Lezione di riferimento: https://wp.me/p4kwmk-4D3
4 
5   Versione 03
6   Sequenza di accensione e spegnimento alternato
7   da destra e sinistra e viceversa di 8 LED.
8 
9   Partenza sequenza con 100 millisecondi e messaggio sulla
10   Serial Monitor per modificare il tempo di
11   accensione e spegnimento del singolo LED (delay)
12    
13   Questo codice è di dominio pubblico
14 */
15 
16// creazione di un array di 8 pin a cui vanno collegati i LED
17// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
19 
20byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};
21 
22// per approfondimenti sull'uso dei tipi di dati
23// si consultino i link:
26 
27// intervallo di accensione/spegnimento
28int ritardoLed = 100;
29 
30// indicatore di direzione di accensione
31byte direzione = 1;
32 
33// indice dell'array per l'accensione del LED
34byte ledCorrente = 0;
35 
36// variabile in cui memorizzare il tempo di accensione di Arduino
37// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
39 
40unsigned long tempoTrascorso;
41 
42// per stampare una sola volta il messaggio sulla Serial Monitor 
43bool abilitaMessaggio = 0;
44 
45void setup() {
46  // inizializzazione della serial monitor
47  Serial.begin(9600);
48                
49  // impostiamo tutti i pin ad output
50  for (byte x=0; x<8; x++) {
51    pinMode(ledPin[x], OUTPUT);
52  }
53 
54  // Memorizzazione del tempo trascorso
55  // dal momento in cui avviamo Arduino
56  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
58  tempoTrascorso = millis();
59}
60 
61void loop() {
62  // consente di visualizzare sulla Serial Monitor
63  // una sola stampa delle stringa
64  if (abilitaMessaggio == 0) {
65    // ritardo che evita la doppia stampa del messaggio
66    delay(200);
67    Serial.print("Inserisci il ritardo in millisecondi: ");
68    abilitaMessaggio = 1;
69  }
70 
71  // Controlla se è disponibile almeno un carattere sulla seriale
72  // La Serial.available() restituisce
73  // 1 se presente un cattere,
74  // 0 se non è presente un carattere
75 
76  // per maggior informazioni sull'uso di parseInt() consultare il link:
78 
79  if (Serial.available())
80  {
81    // in r viene memorizzato il valore inserito
82    // attraverso la Serial Monitor
83    int r = Serial.parseInt();
84    if (r != 0) {
85      ritardoLed = r;
86      Serial.println(ritardoLed);
87 
88      // abilita alla stampa di una nuova stringa:
89      // "Inserisci il ritardo in millisecondi: "
90      abilitaMessaggio = 0;
91    }
92  }
93   
94  // funzione che fa lampeggiare il LED su Arduino
95  lampeggio();
96}
97 
98void lampeggio() {
99  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
100  if ((millis() - tempoTrascorso) > ritardoLed) {
101    cambiaStatoLed();
102    tempoTrascorso = millis();
103  }
104}
105 
106// la funzione cambiaStatoLed() permette di controllare
107// la sequenza di accensione dei LED
108 
109void cambiaStatoLed() {
110  // spegne tutti i LED
111  for (byte x = 0; x < 8; x++) {
112    digitalWrite(ledPin[x], LOW);
113  }
114  // accende il LED corrente
115  digitalWrite(ledPin[ledCorrente], HIGH);
116  // incrementa la variabile direzione
117  ledCorrente += direzione;
118  // cambia la direzione se si arriva alla fine
119  if (ledCorrente == 7) {
120    direzione = -1;
121  }
122  if (ledCorrente == 0) {
123    direzione = 1;
124  }
125}

Continua a leggere

Arduino – lezione 07: lavorare con gruppi di valori e funzioni esterne

Questa settima lezione nasce dalla richiesta di alcuni miei studenti che hanno chiesto chiarimenti in merito all’uso degli array, della chiamata di funzioni esterne al loop e del controllo di flusso.

Per la realizzazione della lezione verrà usato un semplice circuito costituito da pulsanti, resistenze e led.

Fate attenzione che sui pulsanti non utilizzano una resistenza esterna di pull-up, perché abiliteremo la resistenza di pull-up interna di Arduino.

Nel montaggio noterete che ho impiegato un supporto costituito da due breadboard che ho costruito per rendere più agevole la realizzazione di esperienze con Arduino. Ovviamente potrete realizzare il tutto con una singola breadboard.

Lista componenti

  • Scheda Arduino (nel mio caso Arduino UNO Rev3);
  • 4 LED;
  • 4 resistenza da 220 Ohm;
  • 4 pulsanti normalmente aperti.

Schema topografico

Risultato del montaggio


Continua a leggere