Archivi tag: Arduino UNO R4

Arduino UNO R4 WiFi – DAC – generazione di onde sinusoidali, quadre e a dente di sega

Una delle nuove caratteristiche presenti in entrambe le schede Arduino Uno R4, Minima e WiFi, è l’inclusione di un singolo DAC a 12 bit. Questo può generare tensioni di uscita discrete da 0 a 5 volt. Poiché questa funzionalità può essere di estremo interesse nelle attività di laboratorio di Elettronica ne indico di seguito il principio di funzionamento per sviluppare future esercitazioni.

Principio di funzionamento

Un DAC, o Convertitore Digitale-Analogico (in inglese: Digital-to-Analog Converter), è un dispositivo che converte un valore digitale (in binario) in un valore analogico (segnali continui che possono assumere un’infinità di valori all’interno di un intervallo).
Si tratta dell’operazione inversa di quella eseguita da un ADC, o Convertitore Analogico-Digitale, che converte un segnale analogico in una rappresentazione digitale.

Il processo di conversione avviene in tre fasi:

  1. lettura in input dei dati digitali,
  2. conversione in analogico
  3. output del segnale analogico

Il DAC riceve in input un segnale digitale, che è rappresentato da una serie di valori binari (0 e 1), l’elettronica del DAC consente successivamente di convertire i valori binari in un segnale di output analogico che può essere utilizzato per pilotare dispositivi analogici come altoparlanti, motori, o altre apparecchiature che necessitano di un ingresso analogico.

Dal punto di vista pratico un DAC può essere utilizzato per creare un’uscita analogica a partire da un valore digitale utile per molte applicazioni, ad esempio per generare forme d’onda audio, per pilotare dispositivi che richiedono un input analogico, o per creare segnali di tensione variabile. Ad esempio nei sistemi audio un DAC converte i segnali audio digitali (come quelli presenti nei file MP3 o nei CD) in segnali analogici che possono essere riprodotti attraverso altoparlanti o cuffie.

Per semplificare ulteriormente nell’utilizzo con Arduino UNO R4, immaginate di avere un valore digitale che varia da 0 a 4095 (rappresentando un range di 12 bit). Un DAC potrebbe convertire questo valore in una tensione che varia, ad esempio, da 0V a 5V. Quindi, se il valore digitale fosse 512 (circa metà del range), l’uscita del DAC potrebbe essere di circa 0,6V.

Vediamo un esempio pratico.

Lo sketch che segue genera una forma d’onda sinusoidale o, meglio, una forma d’onda sinusoidale “simulata”. La frequenza della forma d’onda sinusoidale viene controllata da potenziometro.

Utilizzeremo un oscilloscopio per visualizzare l’onda sinusoidale, il collegamento è piuttosto semplice, abbiamo bisogno di un potenziometro lineare con una resistenza di 5 KOhm o superiore, io ho utilizzato un potenziometro da 10 KOhm.

La sonda dell’oscilloscopio deve essere connessa al pin A0 che viene usata come uscita del DAC. Il potenziometro ha il pin centrale connesso ad A5 (ingresso del DAC), un pin laterale connesso a 5V sulla scheda e l’altro pin laterale connesso a GND sulla scheda.

Se non possedete un oscilloscopio potete inviare l’output ad un amplificatore audio in modo che possiate ascoltare la tonalità generata, ricordate però che se procedete in questo modo bisogna assicurarsi che il controllo del volume sull’amplificatore sia al minimo, dopo di che lentamente aumentate il volume.

Il codice indicato di seguito è tratto dall’esempio di riferimento sul sito Arduino e all’interno degli esempi dell’IDE su cui ho inserito i commenti tradotti in italiano e fatto una piccola correzione.

La spiegazione del funzionamento la trovate nei commenti.

// Prof. Maffucci Michele
// Arduino UNO R4 Digital-to-Analog Converter (DAC)
// Sketch di esempio tratto da: https://docs.arduino.cc/tutorials/uno-r4-wifi/dac/

// libreria per la generazione di forme d'onda analogiche
#include "analogWave.h"

// Crea un'istanza della classe analogWave, usando il pin DAC
analogWave wave(DAC);

int frequenza = 10; // variabile intera che conterrà la frequenza rilevata

void setup() {
Serial.begin(115200);
// pinMode(A5, INPUT); // non necessaria perchè ingresso analogico
wave.sine(frequenza);
}

void loop() {
// legge un valore analogico dal pin A5 e lo mappa nell'intervallo 0 - 10000 Hz
frequenza = map(analogRead(A5), 0, 1024, 0, 10000);

// Stampa l'aggiornmento dell frequenza impostata sulla serial monitor
Serial.println("La frequenza e' " + String(frequenza) + " hz");

// Imposta la frequenza del generatore di forma d'onda sul valore aggiornato
wave.freq(frequenza);

// aspetta un secondo prima di ripetere la successiv rilevazione
delay(1000);
}

Volutamente ho lasciato commentata nel setup() la riga di codice in cui viene impostato il pinMode del pin A5 perché non è necessario inizializzare un pin Analogico, nell’esempio originale invece viene inizializzata.
A tal proposito per chi inizia con Arduino consiglio la lettura della guida: “Errori comuni nell’uso di Arduino – confondere pin analogici con pin digitali“.

Il risultato sarà il seguente:

E’ possibile quindi generare forme d’onda non solo sinusoidali, la funzione wave permette di impostare:

  • sine – onda sinusoidale
  • square – onda quadra
  • saw – onda a dente di sega

sarà sufficiente sostituire wave.sine(frequenza) presente nella sezione setup() rispettivamente con:

  • wave.square(frequenza);
  • wave.saw(frequenza);

Onda quadra:

Onda a dente di sega:

Buon Making a tutti 🙂

EduRobot MicroMoto – Versione Arduino

Qualche mese fa durante un corso per docenti avevo realizzato EduRobot MicroMoto un piccolo kit robotico nato dalla necessità di realizzare attività di Coding e Robotica che potessero essere sperimentate da un numero elevato di allievi, inclusivo dal punto di vista economico, facile da assemblare e personalizzare.

MicroMoto nasce per essere essenziale, sia nella costruzione che nell’uso quotidiano, con  una forma compatta per essere utilizzato comodamente a scuola, sia aula che in laboratorio o a casa.

Il piccolo MicroMoto è stato adottato da diverse classi 🙂 e ringrazio i colleghi che hanno seguito i miei corsi per aver usato questo progetto. In questi mesi mi sono giunte richieste per la realizzazione di una versione Arduino, nello specifico della versione R4 che permette comunicazione Bluetooth e WiFi con un display per mostrare gli stati del sistema e possibilità di essere programmato in C ed in MicroPython e questa versione la utilizzerò da domani per un corso di robotica indirizzato a docenti.

La modalità costruttiva per questa versione Arduino è la medesima di quella realizzata per la versione BBC micro:bit con scheda motori :MOVE, sono presenti però alcune piccole differenze nella faccia superiore, nel taglio delle palline da Ping Pong utilizzate come Caster Ball e nell’uso di un pacco batteria posto nella parte interna del robot, fate riferimento a questo breve tutorial ed utilizzate il PDF allegato effettuare i tagli.

Ricordo che la modalità per vincolare i motori alla struttura avviene sempre con elastici.

Come già segnalato nel post di presentazione, il design del kit è stato pensato per essere minimale e simmetrico, misurando solamente 10×10 cm. Assomiglia a una piccola scatola, assemblata con colla a caldo, un metodo che non solo garantisce maggiore sicurezza durante il montaggio, ma accelera anche significativamente il processo rispetto alle precedenti versioni che utilizzavano viti, facilitando così tutto il lavoro di costruzione.

Utilizzando cartone come materiale base, il kit permette una grande flessibilità per l’espansione e la personalizzazione. L’uso è quello di un cartone di 4 mm di spessore, ricoperto da un foglio bianco adesivo su cui sono stampati i contorni per il taglio. Questo permette agli studenti di esprimere la loro creatività, colorando e personalizzando le superfici bianche. MicroMoto può essere ulteriormente arricchito incollando pezzi Lego sulle sue superfici, offrendo così una versatile adattabilità a diverse esigenze educative.

Nel corso che sto realizzando verranno aggiunte altre funzionalità:

  • evita ostacoli
  • segui linea
  • segui luce

Allego il file PDF con i profili ritaglio in colore rosso. Nel video allegato ho usato un foglio A4 adesivo bianco, ma è possibile utilizzare anche un comune foglio di carta che potrà essere incollato al cartone.

Di seguito le istruzioni per la costruzione.

Continua a leggere

Arduino UNO R4 WiFi – Visualizzare il livello di una grandezza fisica mediante una barra incrementale sulla matrice LED di Arduino

Come anticipato nelle scorse lezioni vediamo in questo tutorial come visualizzare il livello di una grandezza fisica mediante una barra incrementale sulla matrice LED dell’Arduino UNO R4 WiFi.
Gli esempi mostrati possono essere adattati per qualsiasi tipologia di sensore, per semplicità e rapidità di realizzazione ho scelto di rilevare l’intensità luminosa mediante un LDR. Lascio a voi correzioni e miglioramenti a quanto ho scritto.

La matrice, come sapete è costituita da 8 righe di LED, Il numero di linee LED attive sarà proporzionale all’intensità luminosa rilevata:

  • Livello minimo di intensità = accensione della sola riga 7
  • Livello massimo di intensità = accensione di tutte le righe della matrice

I 6 sketch di esempio che seguono sono molto simili, tutti eseguono la calibrazione del sensore, basata sullo sketch standard che trovate all’interno degli esempi dell’IDE di Arduino. Il codice di calibrazione prevede 5 secondi di analisi che permettono di impostare il livello minimo e massimo della grandezza da misurare. Ho aggiunto per ognuno dei 6 esempi alternative diverse per mostrare sulla matrice di LED il timer di 5 secondi.

Il funzionamento di ogni parte del codice dei 6 sketch, è dettagliato mediante commenti, se avete necessità di chiarimenti non esitate a contattarmi.

Circuito

Il circuito prevede l’utilizzo di:

  • Arduino UNO R4 WiFi
  • LDR
  • Resitore da 10 KOhm

Esempio 01

Il trascorrere del tempo di calibrazione è mostrato dall’accensione sequenziale dei primi 5 LED posti sulla riga n. 7, terminata la fase di calibrazione, dopo 0,5 secondi l’array della matrice viene azzerato e viene poi avviata la rilevazione.

sketch01

// Prof. Maffucci Michele
// 31/07/23
// Visualizzazione livello luminoso su matrice LED Uno R4 WiFi
// con calibrazione sensore e visualizzazione timer di calibrazione
// con l'accensione di 5 LED della matrice

// Esercizio 01

// inclusione della libreria per la gestione della matrice
#include "Arduino_LED_Matrix.h"

// creazione dell’oggetto matrix
ArduinoLEDMatrix matrix;

// inizializzazione dell'array per inizializzare lo stato della matrice
uint8_t frame[8][12] = { 0 };

// pin a cui collegare il sensore
int pinSensore = A0;

// variabile in cui memorizzare il valore letto dal sensore
int valoreSensore = 0;

// variabili per calibrazione lovello minimo e massimo luce ambiente
int sensoreMin = 1023;  // valore minimo sensore
int sensoreMax = 0;     // valore massimo sensore

// contatore passi di calibrazione
int contatore = 0;

// valore del millis al passo precedente
unsigned long millisPrecedente = 0;
// valore del millis attuale
unsigned long millisCorrente = 0;

// intervallo in millisecondi per l'accensione di una riga di LED
const long intervallo = 1000;

// riga LED precedentemente accesa
int precedenteLivello = 0;

void setup() {
  // inizializzazione della velocità della serial monitor
  Serial.begin(115200);

  // avvio della matrice di LED
  matrix.begin();

  // calibrazione del sensore nei primi 5 secondi di avvio di Arduino
  while (millis() < 5000) {

    // memorizzazione dle valore attuale del millis
    millisCorrente = millis();

    // lettura valore
    valoreSensore = analogRead(pinSensore);

    // registra il valore massimo rilevato dal sensore
    if (valoreSensore > sensoreMax) {
      sensoreMax = valoreSensore;
    }

    // registra il valore minimo rilevato dal sensore
    if (valoreSensore < sensoreMin) {
      sensoreMin = valoreSensore;
    }

    // timer
    if (millisCorrente - millisPrecedente >= intervallo) {
      millisPrecedente = millisCorrente;
      frame[7][contatore] = 1;
      matrix.renderBitmap(frame, 8, 12);
      contatore++;
    }
  }
  // accensione dell'ultimo LED al 5' secondo
  frame[7][4] = 1;
  matrix.renderBitmap(frame, 8, 12);

  // attesa di 0,5 secondi prima di spegnere tutti i LED
  delay(500);

  // spegnimento di tutti i LED della matrice
  uint8_t frame[8][12] = { 0 };
  matrix.renderBitmap(frame, 8, 12);
}

// Accensione linee matrice (dalla riga 7)
// maggiore e' il valore numeriico di "livello" (riga LED) più bassa sarà l'intensità luminosa
// minore e' e' il valore numeriico di "livello" (riga LED) più alta sarà l'intensità luminosa

// Livello minimo di intensità = accensione della sola riga 7
// Livello massimo di intensità = accensione di tutte le linee della matrice

void barra(int livello) {
  // spegnimento della riga "livello"
  if (livello > precedenteLivello) {
    for (int y = livello; y >= precedenteLivello; y--) {
      // spegnimento dei 12 LED della riga "livello"
      for (int x = 0; x < 12; x++) {
        frame[y][x] = 0;
      }
      matrix.renderBitmap(frame, 8, 12);
      delay(1);
    }
    // accensione della riga "livello"
  } else {
    for (int y = 7; y >= precedenteLivello; y--) {
      for (int x = 0; x < 12; x++) {
        frame[y][x] = 1;
      }
      matrix.renderBitmap(frame, 8, 12);
      delay(1);
    }
  }
  precedenteLivello = livello;
}

void loop() {

  // per evitare sprechi di memoria viene utilizzata usata una stessa variabile: valoreSensore
  // per memorizzare ad ogni passo valori diversi

  // lettura del valore del sensore
  valoreSensore = analogRead(pinSensore);

  // Forzare il valore all'interno del valore minimo e del massimo nel caso di errori di lettura.
  // Nel caso non si aggiungesse il "constrain" nel caso di errore si blocca l'esecuzione
  valoreSensore = constrain(valoreSensore, sensoreMin, sensoreMax);

  // Il valore minimo di lettura è associato all'accensione della riga 7
  // quindi si rimappa tra 7 e 0
  valoreSensore = map(valoreSensore, sensoreMin, sensoreMax, 7, 0);

  // barra(valoreSensore) è la funzione che gestisce l'accensione delle linee di LED
  barra(valoreSensore);
}

Continua a leggere

Arduino UNO R4 WiFi – usare la matrice LED per esercitarsi con i cicli for

Come segnalato nei precedenti, post sto realizzando le prime lezioni sull’uso di Arduino UNO R4 WiFi per i miei studenti, ma ho pensato di mostrare su queste pagine gli sketch di base che poi utilizzerò per implementare esercitazioni più estese. Gli esempi che seguono hanno l’obiettivo di mostrare l’utilizzo ed il risultato di cicli for annidati che hanno come obiettivo la realizzazioni di semplici animazioni sulla matrice di LED di Arduino, strutture di codice che potranno essere sfruttate ad esempio per visualizzare lo stato di un sensore, il valore di una variabile e molto altro.

Utilizzerò per questi esercizi il “Modo 1” indicato nella lezione precedente in cui veniva creato un array bidimensionale che inizializza e rappresenta lo stato della matrice di LED, se ricordate la struttura da includere all’inizio del codice era la seguente:

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 }
};

Per rendere leggibile e più snello il codice scriverò in altro modo la matrice sopra:

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

Esercizio 1

In questo esercizio vedremo come effettuare il blink della 7 linea di LED sulla matrice, per intenderci la base inferiore della matrice. Le inizializzazioni per l’utilizzo della matrice sono le medesime per tutti gli sketch che seguono.

Vengono definite due funzioni: barraOn() e barraOff() che si occupano di accendere e spegnere la linea 7 della matrice. Il ciclo for incluso nelle due funzioni itererà per 12 volte ponendo ad 1 il valore della linea 7, come potete notare viene vincolata a 7 la y della matrice: frame[7][x]. Nel loop verranno richiamate le due funzioni barraOn() e barraOff() con un delay di 1 secondo. Ricordate che è essenziale ad ogni modifica dello stato della matrice invocare la funzione: matrix.renderBitmap(frame, 8, 12); altrimenti non vedrete nulla sulla matrice

// Prof. Maffucci Michele
// 27/07/23
// Blink striscia led (linea 7) su matrice
// Esercizio 01

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// accensione linea 7 della matrice
void barraOn() {
  //barra
  for (int x=0; x<12; x++){
    frame[7][x] = 1;
  }
}

// spegnimento linea 7 della matrice
void barraOff() {
  //barra
  for (int x=0; x<12; x++){
    frame[7][x] = 0;
  }
}

void loop() {
  barraOn();
  matrix.renderBitmap(frame, 8, 12);

  delay(1000);
  barraOff();

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

Esercizio 2

In questo secondo esercizio l’accensione dei LED dell’ultima line avviene in modo sequenziale da sinistra verso destra e successivamente questi saranno spenti sempre da sinistra verso destra dando l’impressione che il “serpente” esce dallo schermo da destra e rientri da sinistra.

Nell’esempio che segue sono state definite due funzioni: barraOn() e barraOff() in cui vincolata la linea 7 viene modificata in modo ciclico la coordinata x del LED. Per dare la sensazione di movimento l’accensione e lo spegnimento di ogni songolo LEd è stato posto a 100 millisecondi. Nel loop vengono richiamate ciclicamente le due funzioni.

// Prof. Maffucci Michele
// 27/07/23
// Accensione/spegnimento in una direzione striscia led (linea 7) su matrice
// Esercizio 02

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// accensione linea 7 della matrice
void barraOn() {
  for (int x=0; x<12; x++){
    frame[7][x] = 1;
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

// spegnimento linea 7 della matrice
void barraOff() {
  //barra
  for (int x=0; x<12; x++){
    frame[7][x] = 0;
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

void loop() {
  barraOn();
  barraOff();
}

Esercizio 3

In questo esempio la barra posta sulla linea 7 simula il comportamento di incremento o decremento di una variabile per cui la barra aumenta e diminuisce da un valore minimo ad un valore massimo in modo sequenziale, ma immaginate di modificare questo sketch collegandolo ad esempio alla variazione di un valore analogico. La differenza rispetto allo sketch precedente consiste solamente nel fatto che lo spegnimento dei LED avviene partendo dai LED maggiore.

// Prof. Maffucci Michele
// 27/07/23
// Accensione/spegnimento in due direzioni striscia led (linea 7) su matrice
// Esercizio 03

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// accensione linea 7 della matrice
void barraOn() {
  for (int x=0; x<12; x++){
    frame[7][x] = 1;
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

// spegnimento linea 7 della matrice
void barraOff() {
  for (int x=11; x>=0; x--){
    frame[7][x] = 0;
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

void loop() {
  barraOn();
  barraOff();
}

Esercizio 4

L’idea di questo quarto sketch nasce dalla necessità di realizzare un indicatore per misurare ad esempio il livello di luminosità, sonoro o l’umidità presente nel terreno. Come potete notare le linee della matrice vengono attivate una alla volta dal basso verso l’alto e poi spente dall’alto verso il basso. Le due funzioni barraOn() e barraOff() includono due cicli for annidati, quello più esterno consente di fissare la linea della matrice, mentre quello più interno permette di accendere o spegnere i LED sulla stessa linea. Nel loop le due funzioni vengono richiamata ciclicamente.

// Prof. Maffucci Michele
// 27/07/23
// Accensione/spegnimento in due direzioni (linea) BASSO>ALTO ALTO>BASSO matrice led
// Esercizio 04

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// accensione linea BASSO>ALTO (dalla linea 7)
void barraOn() {
  for (int y = 8; y >= 0; y--) {
    for (int x = 0; x < 12; x++) {
      frame[y][x] = 1;
    }
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

// spegnimento linea ALTO>BASSO (dalla linea 0)
void barraOff() {
  for (int y = 0; y <=8 ; y++) {
    for (int x = 11; x >= 0; x--) {
      frame[y][x] = 0;
    }
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

void loop() {
  barraOn();
  barraOff();
}

Esercizio 5

Lo sketch che segue ha il medesimo obiettivo del precedente, ma in questo caso l’accensione e lo spegnimento della matrice avviene per colonne, accensione da sinistra verso destra e spegnimento da destra verso sinistra. Le due funzioni barraOn() e barraOff(), costittuite entrambe da due cicli for annidati funzionano in modalità opposta allo sketch precedente, in questo caso il for più esterno vincola la colonna e quello più interno accende/spegne i LED della colonna.

// Prof. Maffucci Michele
// 27/07/23
// Accensione/spegnimento in due direzioni SX>DX DX>SX (partenza colonna 0) matrice led
// Esercizio 05

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// accensione colonna SX>DX (dalla colonna 0)
void barraOn() {
  for (int x = 0; x < 12; x++) {
    for (int y = 0 ; y < 8; y++) {
      frame[y][x] = 1;
    }
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

// spegnimento colonna DX>SX (dalla colonna 11)
void barraOff() {
  for (int x = 11; x >= 0 ; x--) {
    for (int y = 7 ; y >= 0; y--) {
      frame[y][x] = 0;
    }
    matrix.renderBitmap(frame, 8, 12);
    delay(100);
  }
}

void loop() {
  barraOn();
  barraOff();
}

Esercizio 6

In questo esercizio si vuole mostrare come spostare, “far cadere”, un puntino dall’alto verso il basso eseguendo questa operazione per ogni colonna da sinistra verso destra. La funzione puntino() è costituita da due cicli for, il più esterno vincola la colonna su cui movimentare il LED, mentre quello più interno accende e spegne in modo sequenziale i LED della colonna selezionata dal for più esterno.

// Prof. Maffucci Michele
// 27/07/23
// Accensione e spegnimento sequenziale dall'alto al basso - matrice led
// Esercizio 06

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// puntino cadente
void puntino() {
  for (int x = 0; x < 12; x++) {
    for (int y = 0; y < 8; y++) {
      frame[y][x] = 1;
      matrix.renderBitmap(frame, 8, 12);
      delay(20);
      frame[y][x] = 0;
      matrix.renderBitmap(frame, 8, 12);
      delay(20);
    }
  }
}

void loop() {
  puntino();
}

Esercizio 7

Comportamento identico al precedente ma in questo caso lo spostamento del puntino avviene per righe dall’alto al basso ed accensione e spegnimento da destra verso sinistra. In questo vaso il for più esterno vincola la riga mentre quello più interno si occupa di accendere e spegnere i LED della riga selezionata.

// Prof. Maffucci Michele
// 27/07/23
// Accensione e spegnimento sequenziale SX > DX dall'alto al basso - matrice led
// Esercizio 07

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// puntino cadente
void puntino() {
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 12; x++) {
      frame[y][x] = 1;
      matrix.renderBitmap(frame, 8, 12);
      delay(20);
      frame[y][x] = 0;
      matrix.renderBitmap(frame, 8, 12);
      delay(20);
    }
  }
}

void loop() {
  puntino();
}

Esercizio 8

In questo esercizio viene vincolato lo spostamento del puntino luminoso sulla riga quattro simulando uno spostamento sinistra/destra e destra/sinistra dando l’impressione di un rimbalzo sulle pareti. Per rendere più chiara la lettura da parte degli studenti ho realizzato due funzioni separate che si occupano dei due movimenti.

// Prof. Maffucci Michele
// 27/07/23
// Puntino che rimbalza SX > DX - DX > SX - matrice led
// Esercizio 08

#include "Arduino_LED_Matrix.h"

ArduinoLEDMatrix matrix;

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

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

// puntino rimbalza su riga 4
void puntinoSxDx() {
  for (int x = 0; x < 12; x++) {
    frame[4][x] = 1;
    matrix.renderBitmap(frame, 8, 12);
    delay(50);
    frame[4][x] = 0;
    matrix.renderBitmap(frame, 8, 12);
    delay(50);
  }
}

void puntinoDxSx() {
  for (int x = 11; x >= 0; x--) {
    frame[4][x] = 1;
    matrix.renderBitmap(frame, 8, 12);
    delay(50);
    frame[4][x] = 0;
    matrix.renderBitmap(frame, 8, 12);
    delay(50);
  }
}

void loop() {
  puntinoSxDx();
  puntinoDxSx();
}

Buon Making 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 🙂