Archivi tag: array

Esercitazione 2 – Tastiera 4×4 non bloccante con codice di accesso e feedback di errore

Allenamento per l’esame di maturità
Percorso di laboratorio con Arduino per studenti di quinta ITIS

Obiettivo didattico

Scansionare una tastiera 4×4 senza usare una libreria esterna, acquisire una sequenza di tasti, confrontarla con un codice corretto e fornire un feedback di esito positivo o errore. L’attività allena gestione di matrici di pin, scansione righe/colonne, buffer di input e logica non bloccante.

Materiali suggeriti

  • Arduino UNO R3 o UNO R4;
  • tastiera 4×4;
  • LED verde;
  • LED rosso,
  • buzzer opzionale;
  • 2 resitori da 220 Ohm (per i LED);
  • breadboard;
  • cavetti jumper.

Schema di collegamento

Richiamo teorico

Una tastiera a matrice riduce il numero di fili usando righe e colonne. Il microcontrollore attiva una riga alla volta e legge le colonne. Se una colonna va a livello attivo, il tasto corrispondente a quella riga e colonna è premuto. Anche qui bisogna evitare il rimbalzo e gestire l’ingresso come sequenza di eventi.

Schema logico dell’attività

Il programma scansiona una riga alla volta. Quando rileva un tasto stabile, lo aggiunge al buffer. Se viene premuto # confronta il buffer con il codice atteso. Se il codice è corretto accende il LED verde. Se è errato accende il LED rosso, svuota il buffer e ricomincia.

Diagramma di flusso

Diagramma di flusso Mermaid

flowchart TD
    A[Inizio] --> B[Configura righe, colonne e LED]
    B --> C[Scansione tastiera]
    C --> D{Tasto valido trovato?}
    D -- No --> C
    D -- Sì --> E{Tasto uguale a # ?}
    E -- No --> F[Aggiungi carattere al buffer]
    F --> C
    E -- Sì --> G[Confronta buffer con codice]
    G --> H{Codice corretto?}
    H -- Sì --> I[Feedback verde e reset buffer]
    H -- No --> J[Feedback rosso e reset buffer]
    I --> C
    J --> C

Programma

/*
  Prof. Maffucci Michele
  Esercizio 2: Tastiera 4x4 non bloccante con codice di accesso e feedback di errore
*/

// ---------------------------
// Pin delle 4 righe
// ---------------------------
const int righe[4] = { 2, 3, 4, 5 };

// ---------------------------
// Pin delle 4 colonne
// ---------------------------
const int colonne[4] = { 6, 7, 8, 9 };

// ---------------------------
// Mappa dei tasti
// ---------------------------
char mappaTasti[4][4] = {
  { '1', '2', '3', 'A' },
  { '4', '5', '6', 'B' },
  { '7', '8', '9', 'C' },
  { '*', '0', '#', 'D' }
};

// ---------------------------
// LED di feedback
// ---------------------------
const int PIN_LED_VERDE = 10;
const int PIN_LED_ROSSO = 11;

// ---------------------------
// Codice corretto da inserire
// ---------------------------
char codiceCorretto[] = "2580";

// ---------------------------
// Buffer di ingresso utente
// ---------------------------
char bufferInput[8];
int indiceInput = 0;

// ---------------------------
// Variabili per antirimbalzo
// ---------------------------
char ultimoTastoLetto = '\0';
char ultimoTastoConfermato = '\0';
unsigned long istanteCambio = 0;
const unsigned long TEMPO_DEBOUNCE = 40;

void setup() {
  // Le righe vengono pilotate in uscita.
  for (int i = 0; i < 4; i = i + 1) {
    pinMode(righe[i], OUTPUT);
    digitalWrite(righe[i], HIGH);
  }

  // Le colonne sono ingressi con pull-up.
  for (int i = 0; i < 4; i = i + 1) {
    pinMode(colonne[i], INPUT_PULLUP);
  }

  pinMode(PIN_LED_VERDE, OUTPUT);
  pinMode(PIN_LED_ROSSO, OUTPUT);

  Serial.begin(9600);
  svuotaBuffer();
}

void loop() {
  // Leggo il tasto corrente tramite scansione.
  char tastoCorrente = leggiTastiera();

  // Se è cambiato il valore grezzo, aggiorno il tempo.
  if (tastoCorrente != ultimoTastoLetto) {
    ultimoTastoLetto = tastoCorrente;
    istanteCambio = millis();
  }

  // Se il valore è stabile da abbastanza tempo, lo confermo.
  if ((millis() - istanteCambio) >= TEMPO_DEBOUNCE) {
    if (tastoCorrente != ultimoTastoConfermato) {
      ultimoTastoConfermato = tastoCorrente;

      // Elaboro il tasto solo quando è reale e non nullo.
      if (ultimoTastoConfermato != '\0') {
        gestisciTasto(ultimoTastoConfermato);
      }
    }
  }
}

// ----------------------------------------------------------
// Scansione manuale della tastiera.
// Attivo una riga alla volta e leggo tutte le colonne.
// ----------------------------------------------------------
char leggiTastiera() {
  for (int r = 0; r < 4; r = r + 1) {

    // Prima porto tutte le righe alte.
    for (int i = 0; i < 4; i = i + 1) {
      digitalWrite(righe[i], HIGH);
    }

    // Poi attivo solo la riga corrente.
    digitalWrite(righe[r], LOW);

    // Leggo tutte le colonne.
    for (int c = 0; c < 4; c = c + 1) {
      if (digitalRead(colonne[c]) == LOW) {
        return mappaTasti[r][c];
      }
    }
  }

  // Se non trovo alcun tasto, restituisco nullo.
  return '\0';
}

// ----------------------------------------------------------
// Gestione del carattere ricevuto.
// * cancella, # conferma, altri tasti vengono memorizzati.
// ----------------------------------------------------------
void gestisciTasto(char tasto) {
  Serial.print("Tasto ricevuto: ");
  Serial.println(tasto);

  if (tasto == '*') {
    svuotaBuffer();
    Serial.println("Buffer cancellato");
  } else if (tasto == '#') {
    verificaCodice();
  } else {
    if (indiceInput < 7) {
      bufferInput[indiceInput] = tasto;
      indiceInput = indiceInput + 1;
      bufferInput[indiceInput] = '\0';
    }
  }
}

// ----------------------------------------------------------
// Confronto del buffer con il codice corretto.
// ----------------------------------------------------------
void verificaCodice() {
  bool corretto = true;

  for (int i = 0; codiceCorretto[i] != '\0'; i = i + 1) {
    if (bufferInput[i] != codiceCorretto[i]) {
      corretto = false;
    }
  }

  // Verifico anche la lunghezza.
  if (indiceInput != 4) {
    corretto = false;
  }

  if (corretto == true) {
    Serial.println("CODICE CORRETTO");
    digitalWrite(PIN_LED_VERDE, HIGH);
    delay(500);
    digitalWrite(PIN_LED_VERDE, LOW);
  } else {
    Serial.println("CODICE ERRATO");
    digitalWrite(PIN_LED_ROSSO, HIGH);
    delay(500);
    digitalWrite(PIN_LED_ROSSO, LOW);
  }

  svuotaBuffer();
}

// ----------------------------------------------------------
// Ripulisce il buffer e rimette l'indice a zero.
// ----------------------------------------------------------
void svuotaBuffer() {
  for (int i = 0; i < 8; i = i + 1) {
    bufferInput[i] = '\0';
  }
  indiceInput = 0;
}

Continua a leggere

Allenamento alla maturità con Arduino

Esercitazioni progressive di laboratorio per studenti di quinta ITIS e professionale

Nota importante: questa pagina è in continuo aggiornamento. I link alle diverse esercitazioni saranno aggiunti progressivamente nell’indice, man mano che i contenuti verranno pubblicati.

La preparazione alla seconda prova dell’Esame di Stato passa anche attraverso l’attività pratica in laboratorio in modo che l’azione possa essere utile per focalizzare lo studio teorico e lo svolgimento delle tracce degli anni precedenti.

Per affrontare bene la maturità serve allenamento operativo, metodo e continuità.
Per questo motivo ho deciso di proporre una serie di esercitazioni pratiche con Arduino, pensate per studenti del quinto anno dell’ITIS – Elettronica e Automazione, utilizzabili sia a scuola in laboratorio con il supporto dei docenti sia a casa in autonomia come attività di ripasso e consolidamento.

Sono in realtà attività pratiche che possono essere svolte in circa 90 minuti di lavoro e che prendono in considerazione argomenti del triennio dell’ITIS che ritengo possano servire per lo svolgimento di problemi che potrebbero essere presenti nel tema d’esame di TPSEE.

Quindi questa raccolta nasce con un obiettivo molto preciso:

aiutare gli studenti a prendere confidenza con quelle strutture di programmazione che, molto spesso, risultano più difficili da capire e da usare in modo corretto, ad esempio:

  • temporizzazioni non bloccanti con millis()
  • multitasking cooperativo
  • array e matrici
  • interrupt
  • puntatori
  • macchine a stati
  • gestione ordinata degli eventi

Due percorsi distinti ma complementari

All’interno del lavoro di preparazione alla maturità sto sviluppando due percorsi paralleli.

Il primo è questa serie di esercitazioni trasversali di programmazione, focalizzate sulle strutture software più importanti e spesso più ostiche.

Il secondo, invece, è già in corso con un mia classe e nel breve pubblicherò le attività di laboratorio, si tratta di una reinterpretazione per il laboratorio di Sistemi elettronici e TPSEE della prova di maturità della sessione ordinaria 2018 di TPSEE, che richiede di affrontare un processo articolato con preallarme, attuatori ON/OFF, acquisizione di sensori, scelta dell’intervallo di campionamento, progettazione delle interfacce e descrizione dell’algoritmo di gestione.

Partiamo però dalle 20 attività.

Come sono costruite le esercitazioni

La struttura delle schede di lavoro rispecchia quelle che in genere consegno ai miei studenti.

Ogni attività sarà presentata con una struttura costante, così da aiutare anche gli studenti che hanno competenze di programmazione ancora deboli.

In ogni post troverete:

  • richiamo teorico iniziale delle istruzioni usate
  • analisi semplificata del problema
  • materiali necessari
  • schema logico di funzionamento
  • diagramma di flusso
  • codice Arduino completo e commentato nel dettaglio
  • spiegazione guidata del programma
  • errori tipici
  • possibili estensioni

Attività 0: prima di programmare, capire bene il testo

Prima ancora di partire con la costruzione del circuito e la programmazione iniziamo con l’Attività 0: la comprensione del testo tecnico, è un problema che si riscontra sempre, soprattutto nella comprensione del testo dell’esame di maturità.

Molto spesso gli studenti si bloccano non perché non sanno programmare, ma perché il testo della prova appare lungo, denso e complesso.
Per questo motivo, prima di scrivere codice, è fondamentale allenarsi a:

  • riconoscere ingressi, uscite, sensori e attuatori
  • distinguere dati misurati e condizioni logiche
  • individuare la sequenza del processo
  • separare la parte hardware dalla parte software
  • … e non ultimo progettare in modo ordinato

Pubblicazione delle soluzioni

Le attività saranno pubblicate progressivamente e in ogni attività lo studente troverà un esercizio aggiuntivo di complessità leggermente superiore rispetto a quello proposto.

Ogni esercizio sarà corredato da diagramma di flusso e codice Mermaid per replicare il diagramma di flusso.

Per favorire il ragionamento autonomo, la soluzione completa verrà resa disponibile dopo qualche giorno dalla pubblicazione dell’esercizio, così da lasciare agli studenti il tempo di provare davvero.

Nota importante

Questa serie di attività è attualmente in costruzione. Nel momento stesso in cui pubblico questo post sto ancora sviluppando e affinando le singole esercitazioni; per questo vi chiedo un po’ di pazienza e comprensione se dovessero essere presenti alcune imprecisioni o aspetti da migliorare. Ogni segnalazione, osservazione o suggerimento sarà quindi molto utile per rendere le schede di lavoro più chiare, efficaci e funzionali.

Naturalmente, quanto propongo non ha la pretesa di esaurire tutti i contenuti necessari per affrontare l’Esame di Stato. Si tratta di una mia selezione di attività, costruita a partire dagli argomenti ricorrenti nelle prove degli anni passati e pensata soprattutto per studenti con competenze di livello medio-base. Per questo motivo le esercitazioni possono essere integrate, adattate o modificate in base alle esigenze della classe, al livello di preparazione degli studenti e alle scelte didattiche del docente.

Di seguito trovate l’indice della serie, che al momento può essere considerato una versione beta, anche se con ogni probabilità resterà molto vicino alla struttura definitiva.
Questa pagina verrà aggiornata progressivamente, aggiungendo di volta in volta i link diretti alle singole esercitazioni.

Indice delle esercitazioni che verranno pubblicate

  • Esercitazione 1 – Pulsante singolo con antirimbalzo, doppio clic, pressione lunga e timeout
  • Esercitazione 2 – Tastiera 4×4 non bloccante con codice di accesso e feedback di errore
  • Esercitazione 3 – Scheduler cooperativo con tre task e supervisione dei tempi
  • Esercitazione 4 – Macchina a stati per un ciclo automatico con START, pausa, allarme e reset
  • Esercitazione 5 – Acquisizione analogica calibrata, filtrata e convertita in grandezza fisica
  • Esercitazione 6 – Controllo a finestra con isteresi, allarme latched e reset
  • Esercitazione 7 – Confronto tra filtro a media mobile e filtro esponenziale
  • Esercitazione 8 – Campionamento temporizzato con array di struct: tempo, valore e stato
  • Esercitazione 9 – Analisi statistica di una sequenza con rilevamento anomalie
  • Esercitazione 10 – Buffer circolare con trend, velocità di variazione e soglia dinamica
  • Esercitazione 11 – Matrice bidimensionale per organizzare campioni di più sensori nel tempo
  • Esercitazione 12 – Frame buffer per matrice LED: icone, animazioni e scorrimento testo
  • Esercitazione 13 – Conteggio impulsi con interrupt e validazione evento
  • Esercitazione 14 – Misura di periodo, frequenza, duty cycle e tempo alto di un segnale PWM
  • Esercitazione 15 – Encoder rotativo con menù parametrico semplificato
  • Esercitazione 16 – Funzioni con parametri passati per indirizzo e restituzione di più risultati
  • Esercitazione 17 – Ordinamento di misure e scambio di valori tramite puntatori
  • Esercitazione 18 – Macchina a stati per un menù su display LCD
  • Esercitazione 19 – Parser di comandi seriali con parametri e risposta strutturata
  • Esercitazione 20 – Mini progetto finale: stazione di monitoraggio completa

Quale sarà la periodicità delle attività? Probabilmente giornaliera, da domani o lunedì prossimo.

Siete pronti per ripassare? 🙂

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:

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

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:

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

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à:

/*
 * Prof. Michele Maffucci
 * data 15.03.2021
 *
 * Trovare il valore più grande in un array
 *
 */

// sequenza di 6 voti di uno studente
float sequenzaVoti[] = {3.5, 6.75, 5.5, 9, 7.25, 8.75};

void setup() {
  Serial.begin(9600);

  // la variabile con il numero massimo:

  int votoMassimo = 0;

  for (int i = 0; i < (sizeof(sequenzaVoti) / sizeof(float)); i++) {
    if (sequenzaVoti[i] > votoMassimo) {
      // se il voto corrente è maggiore di quello
      // salvato dentro votoMassimo allora lo copio
      votoMassimo = sequenzaVoti[i];
    }
  }
  Serial.print("Il voto massimo è: ");
  Serial.println(votoMassimo);
  Serial.print("Dimensione in byte dell'array ");
  Serial.println(sizeof(sequenzaVoti));
}

void 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.

 

/* Prof. Michele Maffucci
   30.12.2020
   Lezione di riferimento: https://wp.me/p4kwmk-4D3

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

   Questo codice è di dominio pubblico
 */

// creazione di un array di 8 pin a cui vanno collegati i LED
// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
// http://wp.me/p4kwmk-26e

byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};

// per approfondimenti sull'uso dei tipi di dati
// si consultino i link:
// https://wp.me/p4kwmk-4As
// https://wp.me/p4kwmk-1zF

// intervallo di accensione/spegnimento
byte ritardoLed = 100;

// indicatore di direzione di accensione
byte direzione = 1;

// indice dell'array per l'accensione del LED
byte ledCorrente = 0;

// variabile in cui memorizzare il tempo di accensione di Arduino
// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
// http://wp.me/p4kwmk-1zF

unsigned long tempoTrascorso;

void setup() {
  // impostiamo tutti i pin ad output
  for (byte x=0; x<8; x++) {
    pinMode(ledPin[x], OUTPUT);
  }

  // Memorizzazione del tempo trascorso
  // dal momento in cui avviamo Arduino
  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
  // http://wp.me/p4kwmk-1QG

  tempoTrascorso = millis();
}

void loop() {
  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
  if ((millis() - tempoTrascorso) > ritardoLed) {
    cambiaStatoLed();
    tempoTrascorso = millis();
  }
}

// la funzione cambiaStatoLed() permette di controllare
// la sequenza di accensione dei LED

void cambiaStatoLed() {
  // spegne tutti i LED
  for (byte x=0; x<8; x++) {
    digitalWrite(ledPin[x], LOW);
  }
  // accende il LED corrente
  digitalWrite(ledPin[ledCorrente], HIGH);
  // incrementa la variabile direzione
  ledCorrente += direzione;
  // cambia la direzione se si arriva alla fine
  if (ledCorrente == 7) {
    direzione = -1;
  }
  if (ledCorrente == 0) {
    direzione = 1;
  }
}

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).

/* Prof. Michele Maffucci
   30.12.2020
   Lezione di riferimento: https://wp.me/p4kwmk-4D3

   Versione 02
   Sequenza di accensione e spegnimento alternato
   da destra e sinistra e viceversa di 8 LED controllato
   da un trimmer che permetterà di variare il tempo di accensione
   da 50 millisecondi a 1000 millisecondi (1 secondo).

   Questo codice è di dominio pubblico
 */

// creazione di un array di 8 pin a cui vanno collegati i LED
// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
// http://wp.me/p4kwmk-26e

byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};

// per approfondimenti sull'uso dei tipi di dati
// si consultino i link:
// https://wp.me/p4kwmk-4As
// https://wp.me/p4kwmk-1zF

// intervallo di accensione/spegnimento
int ritardoLed;

// variabile in cui memorizzare il valore restituito dall'analogRead
int val = 0;

// indicatore di direzione di accensione
byte direzione = 1;

// indice dell'array per l'accensione del LED
byte ledCorrente = 0;

// variabile in cui memorizzare il tempo di accensione di Arduino
// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
// http://wp.me/p4kwmk-1zF

unsigned long tempoTrascorso;

void setup() {
  Serial.begin(9600);
  // impostiamo tutti i pin ad output
  for (byte x=0; x<8; x++) {
    pinMode(ledPin[x], OUTPUT);
  }

  // Memorizzazione del tempo trascorso
  // dal momento in cui avviamo Arduino
  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
  // http://wp.me/p4kwmk-1QG

  tempoTrascorso = millis();
}

void loop() {

  // valore analogico letto su A0 inserito con il trimmer
  val = analogRead(A0);

// Togliere il commento per valutare
// valore massimo/minimo del valore restituito
// dall'analogRead in questo modo si potranno
// inserire nella map i valori massimi e minimi
// dell'intervallo di partenza

// Serial.println(val);
// delay(1000);

  // ValMax = 285, ValMin = 719
  // riconvertiti nell'intervallo 50, 1000

  ritardoLed = map(val, 285, 719, 50, 1000);

  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
  if ((millis() - tempoTrascorso) > ritardoLed) {
    cambiaStatoLed();
    tempoTrascorso = millis();
  }
}

// la funzione cambiaStatoLed() permette di controllare
// la sequenza di accensione dei LED

void cambiaStatoLed() {
  // spegne tutti i LED
  for (byte x=0; x<8; x++) {
    digitalWrite(ledPin[x], LOW);
  }
  // accende il LED corrente
  digitalWrite(ledPin[ledCorrente], HIGH);
  // incrementa la variabile direzione
  ledCorrente += direzione;
  // cambia la direzione se si arriva alla fine
  if (ledCorrente == 7) {
    direzione = -1;
  }
  if (ledCorrente == 0) {
    direzione = 1;
  }
}

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.

/* Prof. Michele Maffucci
   30.12.2020
   Lezione di riferimento: https://wp.me/p4kwmk-4D3

   Versione 03
   Sequenza di accensione e spegnimento alternato
   da destra e sinistra e viceversa di 8 LED.

   Partenza sequenza con 100 millisecondi e messaggio sulla
   Serial Monitor per modificare il tempo di
   accensione e spegnimento del singolo LED (delay)

   Questo codice è di dominio pubblico
 */

// creazione di un array di 8 pin a cui vanno collegati i LED
// per ulteriori informazioni sull'uso degli array si consulti il seguente link:
// http://wp.me/p4kwmk-26e

byte ledPin[] = {3, 4, 5, 6, 7, 8, 9, 10};

// per approfondimenti sull'uso dei tipi di dati
// si consultino i link:
// https://wp.me/p4kwmk-4As
// https://wp.me/p4kwmk-1zF

// intervallo di accensione/spegnimento
int ritardoLed = 100;

// indicatore di direzione di accensione
byte direzione = 1;

// indice dell'array per l'accensione del LED
byte ledCorrente = 0;

// variabile in cui memorizzare il tempo di accensione di Arduino
// per ulteriori informazioni sui tipi unsigned long si consulti il seguente link:
// http://wp.me/p4kwmk-1zF

unsigned long tempoTrascorso;

// per stampare una sola volta il messaggio sulla Serial Monitor
bool abilitaMessaggio = 0;

void setup() {
  // inizializzazione della serial monitor
  Serial.begin(9600);

  // impostiamo tutti i pin ad output
  for (byte x=0; x<8; x++) {
    pinMode(ledPin[x], OUTPUT);
  }

  // Memorizzazione del tempo trascorso
  // dal momento in cui avviamo Arduino
  // Per ulteriori informazioni sull'uso di millis() si consulti il seguente link:
  // http://wp.me/p4kwmk-1QG
  tempoTrascorso = millis();
}

void loop() {
  // consente di visualizzare sulla Serial Monitor
  // una sola stampa delle stringa
  if (abilitaMessaggio == 0) {
    // ritardo che evita la doppia stampa del messaggio
    delay(200);
    Serial.print("Inserisci il ritardo in millisecondi: ");
    abilitaMessaggio = 1;
  }

  // Controlla se è disponibile almeno un carattere sulla seriale
  // La Serial.available() restituisce
  // 1 se presente un cattere,
  // 0 se non è presente un carattere

  // per maggior informazioni sull'uso di parseInt() consultare il link:
  // https://wp.me/p4kwmk-4Ah

  if (Serial.available())
  {
    // in r viene memorizzato il valore inserito
    // attraverso la Serial Monitor
    int r = Serial.parseInt();
    if (r != 0) {
      ritardoLed = r;
      Serial.println(ritardoLed);

      // abilita alla stampa di una nuova stringa:
      // "Inserisci il ritardo in millisecondi: "
      abilitaMessaggio = 0;
    }
  }

  // funzione che fa lampeggiare il LED su Arduino
  lampeggio();
}

void lampeggio() {
  // Se sono passati "ritardoLed" millisecondi dall'ultimo cambiamento
  if ((millis() - tempoTrascorso) > ritardoLed) {
    cambiaStatoLed();
    tempoTrascorso = millis();
  }
}

// la funzione cambiaStatoLed() permette di controllare
// la sequenza di accensione dei LED

void cambiaStatoLed() {
  // spegne tutti i LED
  for (byte x = 0; x < 8; x++) {
    digitalWrite(ledPin[x], LOW);
  }
  // accende il LED corrente
  digitalWrite(ledPin[ledCorrente], HIGH);
  // incrementa la variabile direzione
  ledCorrente += direzione;
  // cambia la direzione se si arriva alla fine
  if (ledCorrente == 7) {
    direzione = -1;
  }
  if (ledCorrente == 0) {
    direzione = 1;
  }
}

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