Archivi tag: sistemi

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

Esercitazione 1 – Pulsante singolo con antirimbalzo, doppio clic, pressione lunga e timeout

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

Obiettivo didattico

Realizzare una piccola interfaccia utente con un solo pulsante. Il sistema deve riconoscere una pressione breve, un doppio clic, una pressione lunga e un timeout di inattività. L’attività allena la gestione degli eventi, l’antirimbalzo software e l’uso di millis() senza bloccare il programma.

Nota importante

La comprensione del funzionamento di questo esercizio permetterà lo svolgimento in autonomia dell’esercizio aggiuntivo che trovate al fondo di questa scheda di lavoro.

Materiali suggeriti

  • Arduino UNO R3 o UNO R4;
  • 1 pulsante;
  • 3 LED;
  • 3 resitori (per i LED);
  • breadboard;
  • cavetti jumper.

Schema di collegamento

Richiamo teorico

Per leggere correttamente un pulsante reale bisogna evitare il rimbalzo dei contatti. Si usa quindi una variabile con l’ultima lettura, una temporizzazione di stabilizzazione e una logica a eventi. Con millis() si misura il tempo senza usare delay(), così il programma può continuare a controllare altri compiti.

Schema logico dell’attività

Il programma legge continuamente il pulsante. Se la lettura cambia, attende il tempo di debounce. Quando il livello è stabile, riconosce pressione e rilascio. Dal tempo trascorso ricava l’evento: clic breve, doppio clic oppure pressione lunga. Se non accade nulla per molti secondi, attiva un LED di timeout.

Diagramma di flusso

Diagramma di flusso Mermaid

Ricordo che per realizzare il diagramma di flusso, copiate il codice Mermaid seguendo le indicazioni della lezione: Progettare bene, programmare meglio: diagrammi di flusso – cos’è il formato Mermaid? – Lezione 2/5

flowchart TD
    A[Inizio] --> B[Configura pin e variabili]
    B --> C[Leggi pulsante]
    C --> D{Lettura cambiata?}
    D -- Sì --> E[Salva istante variazione]
    D -- No --> F{Tempo debounce trascorso?}
    E --> F
    F -- No --> C
    F -- Sì --> G{Stato stabile cambiato?}
    G -- No --> H{Timeout inattività?}
    G -- Sì --> I{Pulsante premuto?}
    I -- Sì --> J[Memorizza istante pressione]
    I -- No --> K[Calcola durata pressione]
    K --> L{Pressione lunga?}
    L -- Sì --> M[Genera evento LONG]
    L -- No --> N{Secondo clic entro finestra?}
    N -- Sì --> O[Genera evento DOUBLE]
    N -- No --> P[Attendi possibile secondo clic]
    H -- Sì --> Q[Attiva LED timeout]
    H -- No --> C
    J --> C
    M --> C
    O --> C
    P --> C
    Q --> C

Programma

/*
  Prof. Maffucci Michele
  Esercizio 1: Pulsante singolo con antirimbalzo, doppio clic, pressione lunga e timeout
*/


// ---------------------------
// Definizione dei pin usati
// ---------------------------
const int PIN_PULSANTE = 2;
const int PIN_LED_BREVE = 8;
const int PIN_LED_DOPPIO = 9;
const int PIN_LED_TIMEOUT = 10;

// ---------------------------
// Costanti temporali
// ---------------------------
const unsigned long TEMPO_DEBOUNCE = 30;
const unsigned long SOGLIA_PRESSIONE_LUNGA = 800;
const unsigned long FINESTRA_DOPPIO_CLICK = 350;
const unsigned long TEMPO_TIMEOUT = 5000;

// ---------------------------
// Variabili per antirimbalzo
// ---------------------------
int ultimaLetturaGrezza = HIGH;
int statoStabile = HIGH;
unsigned long istanteUltimaVariazione = 0;

// ---------------------------
// Variabili per eventi utente
// ---------------------------
bool attesaSecondoClick = false;
unsigned long istantePrimoClick = 0;
unsigned long istantePressione = 0;
unsigned long ultimoEventoUtente = 0;

void setup() {
  // Il pulsante usa la resistenza interna di pull-up.
  pinMode(PIN_PULSANTE, INPUT_PULLUP);

  // I tre LED rappresentano tre eventi diversi.
  pinMode(PIN_LED_BREVE, OUTPUT);
  pinMode(PIN_LED_DOPPIO, OUTPUT);
  pinMode(PIN_LED_TIMEOUT, OUTPUT);

  // All'avvio tutti i LED sono spenti.
  digitalWrite(PIN_LED_BREVE, LOW);
  digitalWrite(PIN_LED_DOPPIO, LOW);
  digitalWrite(PIN_LED_TIMEOUT, LOW);

  // La seriale aiuta a vedere quale evento viene riconosciuto.
  Serial.begin(9600);

  // Salvo il tempo iniziale come ultimo evento.
  ultimoEventoUtente = millis();
}

void loop() {
  // Leggo il pulsante in forma grezza.
  int letturaCorrente = digitalRead(PIN_PULSANTE);

  // Se la lettura è cambiata rispetto alla precedente,
  // aggiorno il tempo della variazione.
  if (letturaCorrente != ultimaLetturaGrezza) {
    istanteUltimaVariazione = millis();
    ultimaLetturaGrezza = letturaCorrente;
  }

  // Se il segnale è stabile da abbastanza tempo,
  // posso considerarlo affidabile.
  if ((millis() - istanteUltimaVariazione) >= TEMPO_DEBOUNCE) {

    // Se anche lo stato stabile è cambiato, ho un nuovo evento.
    if (letturaCorrente != statoStabile) {
      statoStabile = letturaCorrente;
      ultimoEventoUtente = millis();
      digitalWrite(PIN_LED_TIMEOUT, LOW);

      // Transizione verso livello basso = pulsante premuto.
      if (statoStabile == LOW) {
        istantePressione = millis();
      }
      // Transizione verso livello alto = pulsante rilasciato.
      else {
        unsigned long durataPressione = millis() - istantePressione;

        // Se la durata supera la soglia, classifico come pressione lunga.
        if (durataPressione >= SOGLIA_PRESSIONE_LUNGA) {
          Serial.println("Evento: PRESSIONE LUNGA");
          lampeggiaLed(PIN_LED_DOPPIO, 2, 120);
          attesaSecondoClick = false;
        }
        else {
          // Se sto già aspettando un secondo clic,
          // verifico la finestra temporale.
          if (attesaSecondoClick == true &&
              (millis() - istantePrimoClick) <= FINESTRA_DOPPIO_CLICK) {
            Serial.println("Evento: DOPPIO CLICK");
            lampeggiaLed(PIN_LED_DOPPIO, 1, 250);
            attesaSecondoClick = false;
          }
          else {
            // Primo clic breve: non lo confermo subito,
            // perché potrei ricevere un secondo clic.
            attesaSecondoClick = true;
            istantePrimoClick = millis();
          }
        }
      }
    }
  }

  // Se è in attesa un secondo clic e la finestra è scaduta,
  // confermo il clic breve.
  if (attesaSecondoClick == true && (millis() - istantePrimoClick) > FINESTRA_DOPPIO_CLICK) {
    Serial.println("Evento: CLICK BREVE");
    lampeggiaLed(PIN_LED_BREVE, 1, 250);
    attesaSecondoClick = false;
  }

  // Se passa troppo tempo senza eventi, attivo il LED di timeout.
  if ((millis() - ultimoEventoUtente) >= TEMPO_TIMEOUT) {
    digitalWrite(PIN_LED_TIMEOUT, HIGH);
  }
}

// ----------------------------------------------------------
// Funzione di servizio: fa lampeggiare un LED alcune volte.
// In questa attività è accettabile usare delay() perché
// la funzione serve solo come feedback visivo di conferma.
// ----------------------------------------------------------
void lampeggiaLed(int pinLed, int numeroLampi, int durata) {
  for (int i = 0; i < numeroLampi; i = i + 1) {
    digitalWrite(pinLed, HIGH);
    delay(durata);
    digitalWrite(pinLed, LOW);
    delay(durata);
  }
}

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 – realizzare un sensore di seduta a pressione con un tubo di gomma

Questa mattina, durante la realizzazione e l’analisi dei problemi per il progetto di PCTO: “misura di sedentarietà delle persone sedute alla scrivania” che stanno realizzando i miei studenti di 3′ Elettronica, è nata l’esigenza di associare un doppio controllo per la valutazione della presenza della persona seduta alla scrivania, un controllo effettuato con PIR HC-SR501 ed un sensore di forza resistivo (FSR) inserito all’interno del cuscino della seduta.

Per evitare l’acquisto di un sensore di forza resistivo e non pesare sulle finanze dei ragazzi le modalità sono tre:

  • richiesta alla scuola
  • compra il Prof.
  • farlo costruire ai ragazzi

l’acquisto da parte della scuola o mia non è un problema, ma la terza soluzione è quella che in questo momento prediligo, perché può essere realizzata in 5 minuti, credo che possa gratificare di più lo studente Maker in erba 🙂 , inoltre ritengo importante che gli allievi assumano la capacità di costruire il sensore perché ne dovranno ottimizzare l’uso, scontrandosi inevitabilmente con una serie di variabili fisiche che dovranno gestire.

Ma come si costruisce il sensore?

E’ indispensabile piccolo tubo cilindrico non trasparente, preferibilmente nero che possa essere compresso e al termine della compressioni ritorni abbastanza velocemente nella sua posizione di riposo. Possiamo ricavare il tubo sguainando un cavo elettrico o cavo di rete, oppure come ho fatto in questo tutorial, prendendo una guaina termorestingente.

Inserire un diodo LED ad un’estremità del cilindro e dalla parte opposta inserire un LDR.
Collegare il sistema nella solita modalità, inserendo in serie al LED un resistore da 220 Ohm e creando un partitore di tensione tra l’LDR e un resistore da 10KOhm, così come indicato nel circuito indicato di seguito.

Come test di funzionamento utilizzare il semplice sketch che trovate di seguito, nei commenti la spiegazione di tutte le parti del codice.

Aprite la Serial Monitor e premete e rilasciate il tubo

/*
 * Prof. Michele Maffucci
 * Data 01.03.2021
 *
 * Oggetto: sensore di seduta a pressione
 *
*/

// variabile in cui verrà memorizzato il valore presente sul pin A0
const int misura = A0;

// valore restituito dall'analogRead
int val = 0;

// pin a cui è connesso il LED del sensore di seduta
int pinLed = 2;

// LED che segnala la seduta della persona
int pinLedAlert = 13;

void setup() {
  // Inizializzazione della Serial Monitor
  Serial.begin(9600);

  // ledPin è il pin a cui è connesso il LED del sensore di seduta
  pinMode(pinLed, OUTPUT);

  // pinLedAlert è il pin a cui è connesso il LED che segnala la seduta della persona
  pinMode(pinLedAlert, OUTPUT);

  // Attivazione del LED del sensore di seduta
  digitalWrite(pinLed, HIGH);

  // Messaggio di avvio
  Serial.println("Sistema di rilevazione seduta");
  Serial.println("-----------------------------");
  Serial.println("");
  delay(1000);
}

void loop() {
  // analogRead leggerà il valore su A0 restituendo un valore tra 0 e 1023
  val = analogRead(misura);

  // il valore di controllo nell'if deve essere sperimentato in funzione
  // delle necessità costruttive (ad es. la lunghezza del tubo)

  // se vero la persona è seduta
  if (val >= 100) {
    digitalWrite(pinLedAlert, HIGH);                      // accensione del LED di avviso
    Serial.println("Persona NON seduta alla scrivania");  // segnalazione di assenza persona
    Serial.print("Valore letto dal sensore = ");          // Stringa di stampa
    Serial.println(val);                                  // Valore restituito dall'AnalogRead
    Serial.println("");                                   // Stampa linea vuota di separazione
    delay(1000);                                          // Intervallo di 1 secondo tra ogni stampa
  }
  else
  {
    digitalWrite(pinLedAlert, LOW);                       // spegnimento del LED di avviso
    Serial.println("Persona seduta alla scrivania");      // segnalazione di presenza persona
    Serial.print("Valore letto dal sensore = ");          // Stringa di stampa
    Serial.println(val);                                  // Valore restituito dall'AnalogRead
    Serial.println("");                                   // Stampa linea vuota di separazione
    delay(1000);                                          // Intervallo di 1 secondo tra ogni stampa
  }
}

Il risultato sulla Serial Monitor è il seguente

Il valore di soglia scelto deve essere ricavato sperimentalmente in funzione della lunghezza e della trasparenza del tubo.

Buon Making a tutti 🙂

Arduino – algebra booleana e funzioni logiche – dai componenti discreti, agli integrati, alla codifica in C

Nuovo Istituto, nuove avventure didattiche. Con le classi di questo nuovo anno scolastico più elettronica e più automazione. Tra gli argomenti che ho rivisto negli scorsi mesi in virtù delle attività che vorrò svolgere, molte sperimentazioni dedicata all’elettronica digitale e all’algebra di Boole, ho riformulato le esercitazioni con componenti discreti che utilizzano i classici integrati TTL 74XX: 7404, 7432, 7408, 7402, 7400, 7486, 74266 corrispondenti alle porte logiche: NOT, OR, AND, NOR, NAND, XOR, XNOR a queste attività aggiungerò, in una fase successiva, la realizzazione delle porte logiche con Arduino, quindi progettazione di semplici shield per la dimostrazione delle tabelle di verità degli operatori logici fondamentali e derivati.

Per rendere più interessante il laboratorio di elettronica, oltre che usare la breadboard, realizzare pcb e saldare, cercherò se il tempo lo permetterà, di far realizzare la scheda Arduino prima su breadboard e poi realizzare una nostra personalissima scheda Arduino con protezioni specifiche sulle uscite digitali ed altro… sogni nel cassetto… vedremo, un passettino alla volta.

Questo articolo è da intendersi come esercitazione e di supporto alla parte teorica ed è dedicata agli studenti delle classi 3′ e 4′ automazione, per lo svolgimento si richiede che gli allievi abbiano seguito un corso base su Arduino. Di seguito senza dilungarmi riprendo alcuni concetti di base che hanno solo l’obiettivo di comprendere meglio la parte sviluppata su Arduino, al fondo due circuiti e due sketch di esempio che potrete migliorare ed espandere.

Avviso per gli studenti

Quest’anno faremo automazione, non solo con PLC ma anche con microcontrollori (Arduino), quindi incominciare a strutturare in C le funzioni logiche sarà essenziale per iniziare a costruire i mattoncini di base dell’automazione, vedremo come costruire altre funzioni nel corso dell’anno.

Premessa (per ripassare velocemente)

I circuiti digitali sono presenti in moltissimi strumenti che utilizzimo ogni giorno, i più noti sono i computer costituiti principalmente da circuiti digitali che, come già sapete, elaborano segnali logici 0 e 1.

Qualsiasi calcolo all’interno di un computer utilizza l’aritmetica binaria e l’adozione di questa aritmetica è stata fatta perché i bit sono rappresentabili in modo semplice tramite dispositivi elettronici in cui è possibile distinguere i 2 stati del potenziale elettrico: high e low a cui si associano i numeri 1 e 0.

Partendo da questi presupposti è possibile costruire un sistema di calcolo che impiega i soli due simboli 0 e 1 che viene chiamato sistema logico binario.

Fu George Boole (1815-1864) che per primo costruì un modello matematico fondato su una logica di tipo binario, tale modello prende il nome di: algebra di Boole.

Come diffusamente esposto durante le lezioni di teoria, l’algebra booleana utilizza equazioni ed espressioni, ma segue le leggi della logica e non quelle dell’aritmetica, per cui le operazioni seguono regole differenti dall’algebra convenzionale.

Le porte logiche realizzano le operazioni logiche dell’algebra binaria.

Porte logiche fondamentali

Somma logica OR

L’operazione può essere effettuata su due o più variabili di ingresso. La somma logica OR assumerà il valore 1 se almeno una delle variabili di ingresso è al valore 1.

Se chiamiamo con A e B le variabili di ingresso e con Y la variabile di uscita, la somma logica assumerà lo stato logico 1 se almeno una delle due variabili assume lo stato logico 1.


si legge A OR B

Nella figura che segue è mostrata la tabella della verità con le quattro possibili combinazioni delle variabili di ingresso A e B è il simbolo logico corrispondente. Nella colonna Y sono indicati i valori dalla variabile di uscita Y che soddisfa la definizione della porta logica OR.

Prodotto logico AND

L’operazione può essere effettuata su due o più variabili di ingresso. Il prodotto logico AND assumerà il valore 1 se tutte le variabili di ingresso assumeranno il valore 1.

Se chiamiamo con A e B le variabili di ingresso e con Y la variabile di uscita, il prodotto logico assumerà lo stato logico 1 solo se tutte le variabili di ingresso sono allo stato 1.

si legge A AND B

Nella figura che segue è mostrata la tabella della verità con le quattro possibili combinazioni delle variabili di ingresso A e B è il simbolo logico corrispondente. Nella colonna Y sono indicati i valori dalla variabile di uscita Y che soddisfa la definizione della porta logica AND.

Negazione NOT

L’operazione può essere effettuata su una sola variabile di ingresso. Se chiamiamo con A la variabile di ingresso e con Y la variabile di uscita, la negazione farà assumere all’uscita il valore opposto a quello applicato all’ingresso.

si legge A NEGATO oppure A COMPLEMENTATO oppure NOT A

Nella figura che segue è mostrata la tabella della verità con le due possibili combinazioni
di A ed il simbolo logico corrispondente. Nella colonna Y è indicato il valore della variabile di uscita Y che soddisfa la definizione della porta logica NOT.

Porte logiche derivate

Sono le porte logiche ottenute partendo da una o più porte logiche fondamentali però poiché sono estremamente importanti per l’elettronica sono rappresentate con un simbolo unico.

Somma logica negata NOR

L’operazione può essere effettuata su due o più variabili di ingresso. Se chiamiamo con A e B le variabili di ingresso e con Y la variabile di uscita, la somma logica negata assumerà lo stato logico 1 solo se tutte le variabili di ingresso sono allo stato 1, in tutti gli altri casi l’uscita assumerà il valore 1.

La somma logica negata corrrisponde al collegamento di una OR seguita da una porta NOT.

si legge A NOR B

Nella figura che segue è mostrata la tabella della verità con le quattro possibili combinazioni delle variabili di ingresso A e B è il simbolo logico corrispondente. Nella colonna Y sono indicati i valori dalla variabile di uscita Y che soddisfa la definizione della porta logica NOR.

Prodotto logico negato NAND

L’operazione può essere effettuata su due o più variabili di ingresso. Il prodotto logico negato NAND assumerà il valore 1 se tutte le variabili di ingresso assumeranno il valore 0, in tutti gli altri casi l’uscita assumerà il valore 1.

Il prodotto logico negato corrrisponde al collegamento di una AND seguita da una porta NOT.

si legge A NAND B

Nella figura che segue è mostrata la tabella della verità con le quattro possibili combinazioni delle variabili di ingresso A e B è il simbolo logico corrispondente. Nella colonna Y sono indicati i valori dalla variabile di uscita Y che soddisfa la definizione della porta logica NAND.

OR esclusivo – XOR

L’operazione può essere effettuata su due o più variabili di ingresso. l’OR esclusivo assumerà il valore 1 e solo se vi è almeno un ingresso che differisce dagli altri, mentre varrà 0 se tutti gli ingressi assumono lo stesso valore.

Nel caso di due variabili di ingresso A e B, l’OR esclusivo assumerà il valore 1 se gli ingressi assumeranno valori diversi e varrà 0 se gli ingressi assumono lo stesso valore.

si legge A OR ESCLUSIVO B oppure A DIVERSO B

Nella seguente figura si mostra la tabella della verità con le quattro possibili combinazioni tra A e B ed il simbolo logico relativo ad una porta XOR. Nella colonna Y si sono posti i valori assunti dall’uscita Y che soddisfa la definizione della porta XOR.

L’OR ESCLUSIVO può essere espresso anche dalla seguente formula:

formula da ricordare quando dovrete implementare il codice C per Arduino che realizza questa funzione.

NOR esclusivo XNOR

L’operazione può essere effettuata su due o più variabili di ingresso. Il NOR esclusivo assumerà il valore 1 se e solo se tutti gli ingressi hanno il medesimo valore logico, è equivalente alla negazione della porta XOR.

Nel caso di due variabili di ingresso A e B, l’XNOR assumerà il valore 1 se gli ingressi assumeranno valori uguali e varrà 0 se gli ingressi assumono valore diverso.

e si legge A NOR ESCLUSIVO B oppure A COINCIDENTE CON B.

Nella seguente figura si mostra la tabella della verità con le quattro possibili combinazioni tra A e B ed il simbolo logico relativo ad una porta XNOR. Nella colonna Y si sono posti i valori assunti dall’uscita Y che soddisfa la definizione della porta XNOR.

Il NOR ESCLUSIVO può essere espresso anche dalla seguente formula:

formula da ricordare quando dovrete implementare il codice C per Arduino che realizza questa funzione.

Porte logiche con Arduino

Partiamo ora con la realizzazione delle porte logiche descritte sompra utilizzando Arduino.

In un precedente post ho descritto quali sono gli operatori logici disponibili all’interno di Arduino

Se gli ingressi A e B li indichiamo con le varibili:

  • pinInA
  • pinInB

e l’uscita Y la indichiamo con

  • pinOutY

usando la notazione in C che ritrovate nel link indicato sopra si otterrà:

OR

Y = A || B

AND

Y = A && B

NOT

Y = !A

NOR

Y = !(A || B)

NAND

Y = !(A && B)

XOR

Y = A ⊕ B = (A && !B) || (!A && B)

XNOR

Y = !(A ⊕ B) = !((A && !B) || (!A && B))

Premesso ciò la scrittura dello sketch è estremamente semplice.

Realizziamo i due ingressi A e B mediante due pulsanti connessi rispettivamente ai pin 8 e 7, mentre l’uscita sarà connessa al pin 9.

/* Michele Maffucci
   08.09.18

   Versione 1 - sostituzione del codice per verificare
   la tabella di verità degli operatori logici
*/

int pinOutY = 9;
int pinInA = 8;
int pinInB = 7;

void setup()
{
  pinMode(pinOutY, OUTPUT);
  pinMode(pinInA, INPUT);
  pinMode(pinInB, INPUT);
}
void loop()
{
  boolean statoInA = digitalRead(pinInA);
  boolean statoInB = digitalRead(pinInB);
  boolean statoOut;

  // --- sostituire l'operatore logico indicata nel commento in fondo ---

  // funzione logica OR
  statoOut = statoInA || statoInB;
  digitalWrite(pinOutY, statoOut);
}

/*
Sostituisci all'interno del loop nella posizione indicata

  // operatore logico OR
  statoOut = statoInA || statoInB;

  // operatore logico AND
  statoOut = statoInA && statoInB;

  // operatore logico NOT
  statoOut = !statoInA;

  // operatore logico NOR
  statoOut = !(statoInA || statoInB);

  // operatore logico NAND
  statoOut = !(statoInA && statoInB);

  // operatore logico XOR
  statoOut = (statoInA && !statoInB) || (!statoInA && statoInB);

  // operatore logico XNOR
  statoOut = !((statoInA && !statoInB) || (!statoInA && statoInB));
*/

Vediamo ora come realizzare uno sketch che permette dalla Serial Monitor di selezionare mediante menù il tipo di porta logica che si intende simulare; quando la selezione viene effettuata da menù la pressione dei pulsanti deve realizzare la tabella di verità della funzione logica selezionata.

Un pulsante aggiuntivo, che chiameremo: “AVVIA MENU'” verrà utilizzato per riavviare il menù di scelta.

Le azioni quindi saranno:

  1. primo avvio – selezione funzione (da 1 a 7) inserendo da tastiera il numero sulla Serial Monitor
  2. verifica della tabella di verità premendo i pulsanti A e B controllando che il LED, che identifica la Y, sarà acceso per un livello logico 1 e sarà spento per un livello logico 0
  3. Cambio funzione logica:
    1. premere il pulsante: “AVVIA MENU'”
    2. seleziono la funzione logica da verificare e ripetere nuovamente dal passo 1

/* Michele Maffucci
   08.09.18

   Versione 2 - scelta dell'operatore logico da menù stampato sulla Serial Monitor.

 All'avvio compare un menù di selezione dell'operatore logico
  1: OR
  2: AND
  3: NOT
  4: NOR
  5: NAND
  6: XOR
  7: XNOR

  Scrivere sulla Serial Monitor il numero corrispondente e con
  i pulsanti A e B verificare la tabella di verità

  La selezione di un altro operatore avviene premendo il pulsante: AVVIA MENU
  che mostrerà nuovamente sulla Serial Monitor il menù di selezione operatore
*/

int pinOutY = 9;
int pinInA = 8;
int pinInB = 7;

int pinChiave = 10;

boolean statoInA;
boolean statoInB;
boolean statoOut;

// array da utilizzare come chiave di stampa
// per le tabelle di verità delle singole funzioni logiche

int chiavi[] = {1, 1, 1, 1, 1, 1, 1};

void setup()
{
  Serial.begin(9600);
  pinMode(pinOutY, OUTPUT);
  pinMode(pinInA, INPUT);
  pinMode(pinInB, INPUT);

  pinMode(pinInB, INPUT);

  // funzione per la stampa sulla Serial Monitor
  // del menù di scelta dell'operatore logico
  stampaMenu();
}

void stampaMenu() {
  Serial.println("---- Seleziona l'operatore logico ----");
  Serial.println("1: OR");
  Serial.println("2: AND");
  Serial.println("3: NOT");
  Serial.println("4: NOR");
  Serial.println("5: NAND");
  Serial.println("6: XOR");
  Serial.println("7: XNOR");
  Serial.println("--------------------------------------");
  Serial.println("");
  Serial.println("");
}

// La funzione di stampa tabella di verità pone a 0 il valore della
// chiave, chiavi[n] = 0, dove n identifica la tabella di verità
// e il valore associato, 1 o 0, indica il fatto di poterla stampare oppure no.
// chiavi[n] = 0 permette di non stampare ciclicamente una stessa tabella
// di verità all'interno dei singoli cicli while presenti nel loop in cui avviene
// il controllo di quale selezione è stata fatta.

void stampaOr() {
  Serial.println("Hai selezionato l'operatore OR");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  0  ");
  Serial.println(" 0  |  1  |  1  ");
  Serial.println(" 1  |  0  |  1  ");
  Serial.println(" 1  |  1  |  1  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[0] = 0;
}

void stampaAnd() {
  Serial.println("Hai selezionato l'operatore AND");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  0  ");
  Serial.println(" 0  |  1  |  0  ");
  Serial.println(" 1  |  0  |  0  ");
  Serial.println(" 1  |  1  |  1  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[1] = 0;
}

void stampaNot() {
  Serial.println("Hai selezionato l'operatore NOT");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  Y  ");
  Serial.println("----|-----");
  Serial.println(" 0  |  1  ");
  Serial.println(" 1  |  0  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[2] = 0;
}

void stampaNor() {
  Serial.println("Hai selezionato l'operatore NOR");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  1  ");
  Serial.println(" 0  |  1  |  0  ");
  Serial.println(" 1  |  0  |  0  ");
  Serial.println(" 1  |  1  |  0  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[3] = 0;
}

void stampaNand() {
  Serial.println("Hai selezionato l'operatore NAND");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  1  ");
  Serial.println(" 0  |  1  |  1  ");
  Serial.println(" 1  |  0  |  1  ");
  Serial.println(" 1  |  1  |  0  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[4] = 0;
}

void stampaXor() {
  Serial.println("Hai selezionato l'operatore XOR");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  0  ");
  Serial.println(" 0  |  1  |  1  ");
  Serial.println(" 1  |  0  |  1  ");
  Serial.println(" 1  |  1  |  0  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[5] = 0;
}

void stampaXnor() {
  Serial.println("Hai selezionato l'operatore XNOR");
  Serial.println("La tabella di verità è:");
  Serial.println(" A  |  B  |  Y  ");
  Serial.println("----|-----|-----");
  Serial.println(" 0  |  0  |  1  ");
  Serial.println(" 0  |  1  |  0  ");
  Serial.println(" 1  |  0  |  0  ");
  Serial.println(" 1  |  1  |  1  ");
  Serial.println("");
  Serial.println("----------------------------------------------------------------");
  Serial.println("Per selezionare un altro operatore premi il pulsante AVVIA MENU'");
  Serial.println("----------------------------------------------------------------");
  Serial.println("");

  mettiUnoChiavi();
  chiavi[6] = 0;
}

void mettiUnoChiavi() {
  for (int indice = 0; indice < 7; indice++) {
    chiavi[indice] = 1;
  }
}

void loop()
{

  if (Serial.available())
  {
    byte selezione = Serial.read();

    while (selezione == '1')
    {
      if (chiavi[0] == 1)
      {
        stampaOr();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      // funzione logica OR
      statoOut = statoInA || statoInB;
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '2')
    {
      if (chiavi[1] == 1) {
        stampaAnd();
      }
      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      // funzione logica AND
      statoOut = statoInA && statoInB;
      digitalWrite(pinOutY, statoOut);
      //selezione = Serial.read();

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '3')
    {
      if (chiavi[2] == 1) {
        stampaNot();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      // funzione logica NOT
      statoOut = !statoInA;
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '4')
    {
      if (chiavi[3] == 1) {
        stampaNor();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      //funzione logica NOR
      statoOut = !(statoInA || statoInB);
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '5')
    {
      if (chiavi[4] == 1) {
        stampaNand();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      //funzione logica NAND
      statoOut = !(statoInA && statoInB);
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '6')
    {
      if (chiavi[5] == 1) {
        stampaXor();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      // funzione logica XOR

      statoOut = (statoInA && !statoInB) || (!statoInA && statoInB);
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }

    while (selezione == '7') {
      if (chiavi[6] == 1) {
        stampaXnor();
      }

      statoInA = digitalRead(pinInA);
      statoInB = digitalRead(pinInB);

      // funzione logica XNOR
      statoOut = !((statoInA && !statoInB) || (!statoInA && statoInB));
      digitalWrite(pinOutY, statoOut);

      if (digitalRead(pinChiave) == HIGH) {
        mettiUnoChiavi();
        stampaMenu();
        break;
      }
    }
  }
}

 

Propongo come esercizio cinque varianti all’esempio precedente:

  1. Gli ingressi selezionati con pulsanti devono essere visualizzati con LED (1 acceso, 0 spento), create inoltre una libreria dedicata per l’implementazione delle funzioni logiche (inserite il codice in un file .h). Per sapere come creare una libreria seguire il link, al fondo del tutorial troverete la spiegazione.
  2. La selezione della funzione logica non avviene più tramite la serial monitor, ma attraverso 7 pulsanti di selezione funzione, la cui selezione deve essere visualizzata con un LED (Acceso = selezionato; Spento= non selezionato). Deve essere presente un pulsante che effettua il reset dell’operazione (non deve essere il reset della scheda Arduino).
  3. Realizzare le stesse funzionalità del punto 2 ma in questo caso non si devono utilizzare LED ma un display 16×2 del tipo Hitachi HD44780, se desiderate potete utilizzare un’interfaccia I2C HD44780 per utilizzare meno pin.
  4. Aggiungere il codice per effettuare il debounce (anti-rimbalzo) sui pulsanti.
  5. Per gli studenti di 4′ superiore realizzare un debounce usando l’elettronica a componenti discreti.

Per chi volesse esplorare nuove frontiere:

  • Realizzate tutto ciò che è stato esposto prima mediante BBC micro:bit e programmate tutto in microPython.
  • Realizzate tutto ciò che è stato esposto prima mediante Raspberry Pi e programmate tutto in Python.

Buon Coding (e studio) a tutti 🙂