Archivi tag: led

Esercitazione 4 – Macchina a stati per un ciclo automatico con start, pausa, allarme e reset

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

Obiettivo didattico

Modellare un ciclo automatico come macchina a stati: attesa, marcia, pausa, allarme e reset. L’attività avvicina gli studenti al modo in cui si progetta un processo tecnico da esame.

Materiali suggeriti

  • Arduino UNO R3 o UNO R4,
  • 3 pulsanti (START, PAUSA, RESET);
  • 2 LED;
  • 2 Resistori da 220 Ohm (per i LED);
  • jumper.

Schema di collegamento

Richiamo teorico

Una macchina a stati finiti rappresenta un processo come un insieme di stati mutuamente esclusivi. In ogni stato il sistema esegue azioni ben definite e attende eventi che causano il passaggio allo stato successivo. Questo metodo riduce gli errori logici nei programmi complessi.

Schema logico dell’attività

  • All’avvio il sistema è in ATTESA;
  • se arriva START passa a MARCIA;
  • in MARCIA può ricevere PAUSA oppure entrare in ALLARME se scade il tempo massimo;
  • in PAUSA attende una nuova pressione di START;
  • da ALLARME si esce solo con RESET, che riporta il sistema in ATTESA.

Diagramma a stati

Per rappresentare in modo corretto il comportamento di questo esercizio è molto utile affiancare al codice un diagramma a stati. In questo caso, infatti, il sistema non si limita a eseguire istruzioni una dopo l’altra, ma cambia comportamento in funzione della condizione operativa in cui si trova.

Il programma può trovarsi in un solo stato per volta, e ogni stato descrive una precisa fase di funzionamento del sistema. Nel nostro sketch gli stati sono quattro:

  • STATO_ATTESA
  • STATO_MARCIA
  • STATO_PAUSA
  • STATO_ALLARME

Il diagramma a stati è particolarmente adatto a questa situazione perché mostra in modo immediato tre aspetti fondamentali:

  • quali sono gli stati possibili del sistema;
  • quali eventi provocano il passaggio da uno stato all’altro;
  • quale logica di funzionamento è stata implementata nel codice.

In altre parole, mentre il diagramma di flusso descrive bene la sequenza dei controlli svolti nel loop(), il diagramma a stati descrive meglio la struttura logica del processo.

Stato iniziale del sistema

Nel diagramma compare il simbolo iniziale che punta verso STATO_ATTESA. Questo significa che, all’accensione di Arduino o dopo un reset, il sistema parte nello stato di attesa.

In questa fase il ciclo automatico non è attivo. Il LED di marcia è spento, il LED di allarme è spento e il programma controlla continuamente i pulsanti in attesa di un comando di avvio.

Dal punto di vista didattico, questo è il comportamento tipico di molti sistemi automatici: il processo non parte in modo autonomo, ma richiede un comando esplicito dell’operatore.

Transizione da ATTESA a MARCIA

Dal nodo STATO_ATTESA parte una freccia verso STATO_MARCIA con l’etichetta:

START premuto / istanteInizioMarcia = millis()

Questa notazione va letta così: se il sistema si trova in attesa e viene rilevata la pressione del pulsante START, allora il programma passa allo stato di marcia. Durante questa transizione viene anche eseguita un’azione importante, cioè il salvataggio dell’istante iniziale della marcia tramite millis().

Questo passaggio è fondamentale perché permette al sistema di iniziare a contare il tempo trascorso in marcia senza bloccare il programma. In pratica, nel momento in cui parte la marcia, viene memorizzato il riferimento temporale da cui inizierà il controllo del timeout.

Significato dello stato MARCIA

Lo stato STATO_MARCIA rappresenta la fase in cui il sistema è attivo.

In questa condizione il LED di marcia viene acceso, il LED di allarme resta spento e il programma continua a controllare due possibili situazioni:

    • la richiesta di pausa;
    • il superamento del tempo massimo consentito.

Importante: nello stato di marcia il sistema non esegue una sola azione, ma resta in una condizione operativa in cui il programma continua a verificare gli eventi che possono modificare il comportamento complessivo del processo.

Transizione da MARCIA a PAUSA

Se durante la marcia viene premuto il pulsante PAUSA, il sistema passa a STATO_PAUSA.

Questa transizione rappresenta una sospensione del ciclo. Dal punto di vista logico, il processo non è terminato, ma è momentaneamente fermo in attesa di un nuovo comando.

Nel diagramma questa freccia mostra che la pausa può essere richiesta solo quando il sistema si trova effettivamente in marcia. Questo rende molto chiaro un concetto fondamentale: non tutti i comandi hanno senso in tutti gli stati. Il significato di un ingresso dipende dallo stato corrente del sistema.

Transizione da MARCIA a ALLARME

La seconda uscita possibile da STATO_MARCIA conduce a STATO_ALLARME ed è attivata dal superamento del tempo massimo di marcia.

Nel codice questa condizione è realizzata confrontando il tempo attuale, ottenuto con millis(), con l’istante iniziale salvato all’ingresso nello stato di marcia. Quando la differenza raggiunge o supera il valore impostato in TEMPO_MASSIMO_MARCIA, il sistema genera l’allarme.

Questo passaggio è interessante perché mostra come una macchina a stati possa cambiare stato non solo in risposta a un pulsante, ma anche in risposta a una condizione temporale. In molti sistemi automatici reali, infatti, il tempo costituisce un vincolo di sicurezza o di controllo del processo.

Significato dello stato PAUSA

Lo stato STATO_PAUSA rappresenta una sospensione controllata del ciclo.

In questa fase il LED di marcia è spento e il LED di allarme è spento. Il programma non torna allo stato iniziale, ma resta in una condizione intermedia da cui il processo può riprendere.

Dal diagramma si vede che da questo stato esiste una sola transizione utile: la pressione di START, che riporta il sistema in STATO_MARCIA.

È importante però osservare un dettaglio del codice: quando si torna in marcia dalla pausa, il programma esegue di nuovo l’istruzione che salva istanteInizioMarcia = millis(). Questo significa che il conteggio del tempo massimo non viene congelato e poi ripreso, ma riparte da zero.

Questo aspetto è importante, perché aiuta a capire che il diagramma descrive la struttura generale del comportamento, mentre le variabili e le azioni associate alle transizioni determinano il comportamento concreto del sistema.

Significato dello stato ALLARME

Lo stato STATO_ALLARME rappresenta una condizione anomala o di sicurezza.

Quando il sistema entra in allarme, il LED di marcia viene spento e il LED di allarme viene acceso. In questo modo l’operatore può riconoscere immediatamente che il ciclo si è interrotto per il superamento del limite previsto.

Dal diagramma si vede che da STATO_ALLARME non si può tornare direttamente in marcia. L’unica uscita prevista è verso STATO_ATTESA, e questa transizione è attivata dal pulsante RESET.

Anche questa è una scelta molto importante dal punto di vista progettuale: in presenza di un allarme il sistema non riparte automaticamente, ma richiede un intervento esplicito da parte dell’operatore. È una logica tipica dei sistemi in cui la sicurezza o il controllo delle anomalie hanno priorità sulla continuità del funzionamento.

IMPORTANTE

Quando si studiano le macchine a stati è utile distinguere tra:

      • azioni di stato, cioè ciò che il sistema fa mentre si trova in un determinato stato;
      • azioni di transizione, cioè ciò che il sistema esegue nel momento in cui passa da uno stato a un altro.

Nell’esercizio proposto, l’accensione o lo spegnimento dei LED, è un’azione associata allo stato, perché avviene nel blocco di codice relativo a ciascun case.

Il salvataggio di istanteInizioMarcia, invece, è un’azione di transizione, perché viene eseguito nel momento in cui il sistema entra nello stato di marcia.
Questa distinzione è molto utile per comprendere meglio sia il diagramma sia il codice.

Continua a leggere

Esercitazione 3 – Scheduler cooperativo con tre task e supervisione dei tempi

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

Obiettivo didattico

Organizzare il programma come scheduler cooperativo con tre task indipendenti: acquisizione analogica, lampeggio di stato e trasmissione seriale periodica. L’attività mostra come il loop() possa diventare un piccolo supervisore software.

Materiali suggeriti

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

Schema di collegamento

Richiamo teorico

In un sistema embedded semplice non si usa un vero sistema operativo, ma si può costruire uno scheduler cooperativo con millis(). Ogni task possiede il proprio intervallo e il proprio istante dell’ultima esecuzione. Il loop() controlla se ciascun task è pronto e lo richiama.

Schema logico dell’attività

Il programma inizializza i timer dei tre task. Nel loop legge il tempo corrente e verifica uno dopo l’altro se è il momento di eseguire il task di acquisizione, quello di segnalazione e quello di stampa seriale. Se il tempo non è scaduto, passa al controllo successivo.

Diagramma di flusso

Diagramma di flusso Mermaid

flowchart TD
    A[Inizio] --> B[Configura pin, seriale e timer]
    B --> C[Leggi tempo attuale]
    C --> D{Task acquisizione pronto?}
    D -- Sì --> E[Esegui acquisizione]
    D -- No --> F{Task LED pronto?}
    E --> F
    F -- Sì --> G[Commuta LED di stato]
    F -- No --> H{Task seriale pronto?}
    G --> H
    H -- Sì --> I[Invia dati in seriale]
    H -- No --> J[Ritorna al loop]
    I --> J
    J --> C

Programma

/*
  Prof. Maffucci Michele
  Esercizio 3: scheduler cooperativo con tre task indipendenti
*/

const int PIN_SENSORE = A0;
const int PIN_LED_STATO = 8;
const int PIN_LED_SOGLIA = 9;

// ---------------------------
// Intervalli dei tre task
// ---------------------------
const unsigned long PERIODO_ACQUISIZIONE = 50;
const unsigned long PERIODO_LED = 300;
const unsigned long PERIODO_SERIALE = 500;

// ---------------------------
// Istanti ultima esecuzione
// ---------------------------
unsigned long ultimoTaskAcquisizione = 0;
unsigned long ultimoTaskLed = 0;
unsigned long ultimoTaskSeriale = 0;

// ---------------------------
// Variabili condivise
// ---------------------------
int valoreGrezzo = 0;
float tensione = 0.0;
bool statoLed = false;

void setup() {
  pinMode(PIN_LED_STATO, OUTPUT);
  pinMode(PIN_LED_SOGLIA, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // Il loop assume il ruolo di piccolo scheduler.
  unsigned long adesso = millis();

  // ---------------------------
  // Task 1: acquisizione
  // ---------------------------
  if ((adesso - ultimoTaskAcquisizione) >= PERIODO_ACQUISIZIONE) {
    ultimoTaskAcquisizione = adesso;
    taskAcquisizione();
  }

  // ---------------------------
  // Task 2: LED di stato
  // ---------------------------
  if ((adesso - ultimoTaskLed) >= PERIODO_LED) {
    ultimoTaskLed = adesso;
    taskLed();
  }

  // ---------------------------
  // Task 3: seriale
  // ---------------------------
  if ((adesso - ultimoTaskSeriale) >= PERIODO_SERIALE) {
    ultimoTaskSeriale = adesso;
    taskSeriale();
  }
}

// ----------------------------------------------------------
// Legge il sensore e calcola una tensione equivalente.
// ----------------------------------------------------------
void taskAcquisizione() {
  valoreGrezzo = analogRead(PIN_SENSORE);

  // Conversione esplicita ADC -> tensione.
  tensione = (valoreGrezzo * 5.0) / 1023.0;

  // Uso della misura per attivare un LED di soglia.
  if (tensione >= 2.50) {
    digitalWrite(PIN_LED_SOGLIA, HIGH);
  } else {
    digitalWrite(PIN_LED_SOGLIA, LOW);
  }
}

// ----------------------------------------------------------
// Task di segnalazione periodica.
// ----------------------------------------------------------
void taskLed() {
  if (statoLed == false) {
    statoLed = true;
    digitalWrite(PIN_LED_STATO, HIGH);
  } else {
    statoLed = false;
    digitalWrite(PIN_LED_STATO, LOW);
  }
}

// ----------------------------------------------------------
// Task di comunicazione seriale.
// ----------------------------------------------------------
void taskSeriale() {
  Serial.print("ADC = ");
  Serial.print(valoreGrezzo);
  Serial.print("  Tensione = ");
  Serial.print(tensione, 2);
  Serial.println(" V");
}

Continua a leggere

BBC microbit – Pixel per Pixel – uso dell’Istruzione plot

Nel corso delle nostre avventure creative durante il corso “Carta, Cartone e Coding”, abbiamo esplorato attività in cui la creatività e l’arte incontra la tecnologia, trasformando idee astratte in realtà tangibili. Uno degli strumenti che abbiamo utilizzato per dare vita alle nostre creazioni è il BBC micro:bit.

Tra le numerose domande che mi avete inviato via mail alcune fanno riferimento all’uso dell’istruzione “plot”. Capisco che, per chi si avvicina per la prima volta a questi concetti, ci possano essere alcuni dubbi su come funzioni esattamente e su come possa essere applicata in modo efficace nelle nostre attività didattiche e in questo breve post voglio fornirvi una possibile soluzione che sfrutto molto spesso per mostrare il comportamento di istruzioni for nidificate.

L’istruzione “plot” è estremamente utile quando lavoriamo con il display LED del micro:bit, che come sapete è costituito da una matrice composto da 25 LED disposti in una griglia 5×5. L’istruzione plot ci permette di accendere un singolo LED sulla griglia, specificando le sue coordinate (x, y).

Come funziona?

  • x rappresenta la posizione orizzontale del LED, partendo da 0 (il lato più a sinistra) fino a 4 (il lato più a destra).
  • y indica la posizione verticale, anch’essa partendo da 0 (in alto) fino a 4 (in basso).

Utilizzando “plot(x, y)”, possiamo quindi selezionare esattamente quale LED accendere, permettendoci di creare disegni, lettere, numeri o qualsiasi altro tipo di segnale visivo che possiamo immaginare.

Vediamo alcuni semplici esempi.

Esempio 01

Accensione sequenziale di tutti i LED sul display del micro:bit dall’alto verso il basso, un colonna alla volta partendo dall’angolo in alto a sinistra del display.

Link al programma.

Esempio 02

Movimento di una pallina sul display. Accensione sequenziale dei LED sul display del micro:bit dall’alto verso il basso, un colonna alla volta partendo dall’angolo in alto a sinistra del display. Il ciclo si ripete all’infinito.

Link al programma.

Esempio 03

Accensione sequenziale di tutti i LED sul display del micro:bit dall’alto verso il basso, un colonna alla volta partendo dall’angolo in alto a sinistra del display, con cancellazione finale del display e ripartenza sequenza.

Link al programma.

Per tutti gli esercizi invertendo nei cicli for le variabili “x” e “y” si avrà un movimento da destra verso sinistra.

Buon Coding a tutti 🙂

Usare la matrice LED di Arduino UNO R4 WiFi

L’elemento caratterizzante più evidente di Arduino R4 è senza alcun dubbio la matrice di LED, che potremo utilizzare come sistema di output immediato, ma anche per creare animazioni o giochi, o ancora mettere in evidenza lo stato di un sensore. La matrice LED è costituita da 12×8 LED.

La matrice e la sua API sono sviluppate per essere programmate in diversi modi, ciascuno adatto per diverse applicazioni. Questa breve lezione vi guiderà attraverso i concetti di base per gestire la matrice di LED aiutandovi a creare le vostre animazioni, mostrando tre diversi metodi di gestione dei LED che potrete scegliere in funzione del progetto che desiderate implementare.

Per lo svolgimento di questa lezione avete necessità solamente della scheda Arduino UNO R4 e di un cavo USB C.

Inizializzare la matrice

L’inizializzazione della matrice di LED avviene in 3 passi:

  1. inclusione nel vostro sketch della libreria:
#include "Arduino_LED_Matrix.h"
  1. creazione dell’oggetto matrix aggiungendo la seguente riga:
ArduinoLEDMatrix matrix;

L’oggetto ovviamente potrà avere un nome a vostro piacimento nell’esempio è stato scelto: “matrix”

  1. avviare la matrice aggiungendo nel setup():
matrix.begin();

Il codice di avvio sarà il seguente:

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup() {
  Serial.begin(115200);
  matrix.begin();
}

Come realizzare un frame

Il principio di funzionamento della libreria di gestione della matrice di LED è quello basato sulla creazione di un frame (fotogramma) memorizzato in un buffer di memoria e poi visualizzato.

Un frame è ciò che viene chiamato anche “immagine” visualizzata in un dato momento sulla matrice di LED. Un’animazione è costituita da una serie di immagini pertanto possiamo dire in altro modo che un’animazione è costituita da una sequenza di frame .

Per controllare la matrice LED 12×8 è indispensabile utilizzare uno spazio in memoria che sia di almeno 96 bit e la libreria fornisce due modi per farlo.

Modo n. 1

Il primo è quello di creare un array bidimensionale di byte nel modo che segue:

byte frame[8][12] = {
  { 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0 },
  { 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 },
  { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
  { 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 },
  { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

La prima modalità è molto semplice da capire, la struttura frame rappresenta la matrice di LED e la serie di 1 indicherà quali LED saranno accesi, mentre quelli a 0 rappresentano i LED spenti. L’array sopra permetterà di visualizzare sulla matrice un cuore.

Suggerimento: Potete vedere il cuore più facilmente se evidenziate tutti gli “1” sulla pagina premendo CTRL/command + F e cercando “1”.

Per fare riferimento ad un pixel specifico ricordare che l’origine degli assi si trova in alto a sinistra ed avrà coordinate (0, 0) pertanto il codice che segue permette di porre ad 1 (on) il terzo pixel da sinistra e secondo dall’alto:

frame[2][1] = 1;
matrix.renderBitmap(frame, 8, 12);

Questo metodo però richiede più memoria di quella necessaria. Anche se ogni LED ha bisogno solo di un singolo bit per memorizzare il suo stato, vengono usati per ognuno di esse otto bit (un byte). Il metodo più efficiente, in termini di memoria per memorizzare un fotogramma è utilizzare un array di interi a 32 bit, descritto di seguito.

Vedremo ora come realizzare uno o più fotogrammi, realizzazione che può anche essere svolta con il LED Matrix tool messo a disposizione da Arduino, ma al fine di comprenderne a pieno il funzionamento, consiglio di seguire le indicazioni che trovate di seguito.

La parte di programma che utilizza codici esadecimali e rappresenta l’immagine del cuore indicata sopra è:

unsigned long frame[] = {
  0x3184a444,
  0x42081100,
  0xa0040000
};

Una variabile long senza segno contiene 32 bit, quindi per gestire 92 LED (bit) avremo necessità di 96/32 che corrisponde a 3 variabili long in grado di rappresentare ogni immagine che appare sulla matrice di LED, pertanto un array di tre variabili long senza segno è un modo efficiente per contenere tutti i bit necessari per rappresentare un’immagine sulla matrice di LED.

Ma come sono relazionate la serie dei 3 valori esadecimali con la posizione di ogni songolo pixel?

Ciò dovrà essere fatto convertendo i valori esadecimali in binario utilizzando il codice che segue:

for (int b = 0; b < 3; b++) {
    Serial.println(frame[b], BIN);
  }

Che permetterà di stampare tutti i valori dei bit dell’array. L’output sarà il seguente:

110001100001001010010001000100
1000010000010000001000100000000
10100000000001000000000000000000

Questo metodo, però, non mostra tutti i bit. Ogni elemento dell’array deve avere 32 bit. Se completiamo correttamente, aggiungendo gli zeri mancanti alla fine avremo i 32 bit di ogni elemento:

00110001100001001010010001000100
01000010000010000001000100000000
10100000000001000000000000000000

Ora suddividiamo il blocco precedente in gruppi da 12 bit ed otterremo nuovamente l’immagine del cuore:

001100011000
010010100100
010001000100
001000001000
000100010000
000010100000
000001000000
000000000000

Se si hanno diversi fotogrammi, è possibile caricarli e visualizzarli in questo modo:

const uint32_t felice[] = {
    0x19819,
    0x80000001,
    0x81f8000
};

const uint32_t cuore[] = {
    0x3184a444,
    0x44042081,
    0x100a0040
};

  matrix.loadFrame(felice);
  delay(500);

  matrix.loadFrame(cuore);
  delay(500);

Proviamo il codice

Applichiamo questi concetti con due sketch che visualizzano fotogrammi diversi sulla tua scheda.

Esempio 01

Creiamo prima 3 fotogrammi interi a 32 bit e carichiamoli sulla scheda uno alla volta.

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup() {
  Serial.begin(115200);
  matrix.begin();
}

const uint32_t felice[] = {
    0x19819,
    0x80000001,
    0x81f8000
};
const uint32_t cuore[] = {
    0x3184a444,
    0x44042081,
    0x100a0040
};

void loop(){
  matrix.loadFrame(felice);
  delay(500);

  matrix.loadFrame(cuore);
  delay(500);
}

Lo sketch è molto semplice è permette di mostrate due stati diversi.

Esempio 02

Cambiamo ora approccio è creiamo un’immagine che cambia durante l’esecuzione del programma. Il programma include diverse funzioni che concorrono alla costruzione del volto e modificano alcuni pixel che permettono di fare l’occhiolino dall’occhio sinistro.

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

void setup() {
  Serial.begin(115200);
  matrix.begin();
}

uint8_t frame[8][12] = {
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};

void occhioSinistro() {
  //Occhio sinistro
  frame[1][3] = 1;
  frame[1][4] = 1;
  frame[2][3] = 1;
  frame[2][4] = 1;
}

void occhiolino() {
  //Fare un occhiolino con occhio sinistro
  frame[1][3] = 0;
  frame[1][4] = 0;
  frame[2][3] = 1;
  frame[2][4] = 1;
}

void occhioDestro() {
  //Occhio destro
  frame[1][8] = 1;
  frame[1][9] = 1;
  frame[2][8] = 1;
  frame[2][9] = 1;
}

void bocca() {
  //Bocca
  frame[5][3] = 1;
  frame[5][9] = 1;
  frame[6][3] = 1;
  frame[6][4] = 1;
  frame[6][5] = 1;
  frame[6][6] = 1;
  frame[6][7] = 1;
  frame[6][8] = 1;
  frame[6][9] = 1;
}

void loop() {
  occhioSinistro();
  occhioDestro();
  bocca();

  matrix.renderBitmap(frame, 8, 12);

  delay(1000);
  occhiolino();

  matrix.renderBitmap(frame, 8, 12);
  delay(1000);
}

Esempio 03

Vediamo ora come, usando il LED Matrix tool, possono essere realizzati due visi sorridenti di cui uno che fa l’occhiolino.
Lascio a voi capire come usare gli strumenti da disegno, essenziale però descrivervi come effettuare il download dei frame.
Costruire due immagini una che riporta un viso con sorriso e l’altra un viso con sorriso che fa l’occhiolino:

Esportare il codice:

aprire il file scaricato: animazione.h ed includerlo all’interno del codice:

#include "Arduino_LED_Matrix.h"
#include <stdint.h>

ArduinoLEDMatrix matrix;

const uint32_t animazione[][4] = {
	// viso sorridente - frame n. 0
  {
		0x18c18,
		0xc0000000,
		0x1041fc,
		66
	},
  // viso sorridente con occhiolino - frame n. 1
	{
		0xc18,
		0xc0000000,
		0x1041fc,
		66
	}
};

void setup() {
  // inizializzazione della seriale
  Serial.begin(115200);
  // avvio della matrice di LED
  matrix.begin();
}

void loop() {
  // caricamento dalla prima animazione e visualizzazione su display
  matrix.loadFrame(animazione[0]);
  // attesa di 1 secondo
  delay(1000);

  // caricamento dalla seconda animazione e visualizzazione su display
  matrix.loadFrame(animazione[1]);
  // attesa di 1 secondo
  delay(1000);
}

Esempio 04

Vediamo ora come sincronizzare la visualizzazione alternata delle due immagini con il lampeggio del LED L. Nel setup() bisognerà impostare il pin a cui è connesso il LED L ad output, dopo di che richiamare accensione e spegnimento eattamente nella stessa posizione in cui viene richiamata la funzione matrix.loadFrame():

#include "Arduino_LED_Matrix.h"
#include <stdint.h>

ArduinoLEDMatrix matrix;

const uint32_t animazione[][4] = {
	// viso sorridente - frame n. 0
  {
		0x18c18,
		0xc0000000,
		0x1041fc,
		66
	},
  // viso sorridente con occhiolino - frame n. 1
	{
		0xc18,
		0xc0000000,
		0x1041fc,
		66
	}
};

void setup() {
  // inizializzazione della seriale
  Serial.begin(115200);
  // avvio della matrice di LED
  matrix.begin();
  // pin a cui collegato il LED L (pin 13) impostato come output
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // caricamento dalla prima animazione e visualizzazione su display
  matrix.loadFrame(animazione[0]);
  // accensione del LED L
  digitalWrite(LED_BUILTIN, HIGH);
  // attesa di 1 secondo
  delay(1000);

  // caricamento dalla seconda animazione e visualizzazione su display
  matrix.loadFrame(animazione[1]);
  // spegnimento del LED L
  digitalWrite(LED_BUILTIN, LOW);
  // attesa di 1 secondo
  delay(1000);
}

Buon Making a tutti 🙂

Esercitazioni di base di Arduino – visualizzazione luminosità LED mediante una barra di avanzamento su display 16×2


Continuo nell’aggiornamento delle esercitazioni di base per gli studenti di 3′ dell’ITIS (Elettronica ed Automazione) e per gli utenti che iniziano con Arduino.
Utilizzeremo un display LCD 16×2 di tipo I2C su cui visualizzeremo mediante una barra di avanzamento, la quantità di luminosità impostata per il LED, mediante un potenziometro.

Per la gestione di un display LCD di tipo I2C rimando alla mia lezione: Utilizzo dell’LCD 16×2 Hitachi HD44780 1602 con modulo I2C PCF8574T.

Per la creazione di caratteri personalizzati rimando alla mia lezione: Disegnare caratteri personalizzati con Arduino per un LCD 16×2.

Lista componenti

  • N.1 Arduino UNO
  • N.1 Breadboard
  • N.1 LCD 16×2 I2C
  • N.1 Potenziometri da 10 KOhm
  • N.1 LED da 5 mm
  • N.1 Resistore da 220 Ohm
  • jumper

Schema di collegamento

Scketch

Di seguito viene indicato il codice i base, all’interno i commenti che ne dettagliano il funzionamento di ogni parte:

/*
   Prof. Maffucci Michele
   https://www.maffucci.it
   Ver.1 - 27.12.21
   Controllo di luminosità LED con
   visualizzazione intensità mediante una
   barra di avanzamento su display 16x2
*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

byte pinPot = A0;           // pin analogico 0 a cui connettere il potenziometro per controllare la luminosità
byte pinLed = 3;            // pin PWM a cui connettere il LED
int  analogVal = 0;         // variabile in cui memorizzare il valore impostato dal potenziometro
int  luminosita = 0;        // variabile in cui memorizzare la luminosità
byte barraAvanzamento = 0;  // indice barra avanzamento

// Per maggiori informazioni sulla realizzazione di caratteri speciali:
// https://www.maffucci.it/2020/01/18/disegnare-caratteri-personalizzati-con-arduino-per-un-lcd-16x2/

// Carattere personalizzato per disegnare la barraAvanzamento di avanzamento
byte iconaBarra[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
};

// inizializzazione della libreria in cui è descritta la modalità di utilizzo dei pin
// impostazione dell'indirizzo dell'LCD 0x27 di 16 caratteri e 2 linee
LiquidCrystal_I2C lcd(0x27, 16, 2);
//-----------------------------

void setup()
{
  lcd.begin();      // inizializzazione dell'LCD
  lcd.backlight();  // attivazione della retroilluminazione

  // Inpostazione ad OUTPUT del pin a cui connettiamo il LED
  pinMode(pinLed, OUTPUT);

  // Cancella il display
  lcd.clear();

  // Stampa il messaggio sulla prima riga del display
  lcd.print("Luminosita' LED");

  //Creazione del carattere per la barra di avanzamento
  lcd.createChar(0, iconaBarra);
}

// Per maggiori informazioni sull'uso del display 16x2 I2C:
// https://www.maffucci.it/2019/01/25/utilizzo-delllcd-16x2-hitachi-hd44780-1602-con-modulo-i2c-pcf8574t/
//-----------------------------

void loop() {
  // Cancella il display
  lcd.clear();

  // Stampa il messsaggio sulla prima riga
  lcd.print("Luminosita' LED");

  //Posiziona il cursore nella seconda riga, prima colonna
  lcd.setCursor(0,1);

  // Lettura del valore impostato dal potenziometro
  analogVal = analogRead(pinPot);

  // Conversione del valore analogico impostato con il potenziometro
  // in Duty Cicle per impostare la luminosità del LED
  luminosita=map(analogVal, 0, 1024, 0, 255);

  // Impostazione della luminosità del LED
  analogWrite(pinLed, luminosita);

  // Conversione della luminosità in quantità di caratteri della barra da stampare
  barraAvanzamento=map(luminosita, 0, 255, 0, 15);

  // Stampa la barra di avanzamento
  for (byte i = 0; i < barraAvanzamento; i++)
  {
    lcd.setCursor(i, 1);
    lcd.write(byte(0));
  }
  // leggero ritardo di 500 ms per visualizzare la barra
  delay(500);
}

Proposta esercizi

Esercizio 1
Nell’esempio proposto viene utilizzato un delay() finale per permettere la visualizzazione dei caratteri sul display. Sostituire il delay() ed utilizzare l’istruzione millis() per valutare il tempo trascorso e controllare la stampa dei caratteri sul display.

Esercizio 2
Modificare il programma precedente raddoppiando il numero di caratteri che rappresenta la barra di avanzamento.

Esercizio 3
Modificare l’esercizio proposto variando la barra di avanzamento in funzione dell’approssimarsi al valore massimo o minimo della luminosità.

Esercizio 4
Modificare l’esercizio proposte inserendo un buzzer che emette un suono la cui frequenza varia in funzione dell’intensità luminosa del LED.

Buon Making a tutti 🙂