Kit Kuman Arduino UNO R3- Dot Matrix

Dopo il Sensore di Fiamma mi sono cimentato con la Matrice di LED 1588BS.

Ho tribolato parecchio perché non capivo il funzionamento. Le difficoltà per un principiante – come me – sono le seguenti:

  1. La matrice è composta da 64 LED disposti in 8 righe da 8 colonne (8×8 = 64)
  2. Nella parte inferiore presenta 8+8 PIN (16 in tutto) che governano righe e colonne in un certo modo (che poi vi spiego)
  3. Arduino UNO non dispone di 16 uscite digitali, quindi, bisogna ricorrere anche a quelle analogiche per gestire la matrice.
  4. La matrice ha una discreta dimensione, quindi, non si riesce – almeno non facilmente – a piazzare su un’unica breadboard; nel mio caso ne ho usato una grande e una piccola.
  5. Su ogni Catodo (alcuni PIN della matrice sono catodi [-] e altri anodi [+]) è opportuno mettere una resistenza da 220 Ohm e, non essendo particolarmente chiara la documentazione fornita da Kuman (ma anche quella che ho trovato in rete è chiara il giusto), ho faticato molto a capire come andavano eseguiti i collegamenti.
Implementazione della Lezione 6 del Kit Kuman Arduino UNO r3

Devo fare subito un avvertimento riguardo alla mia implementazione della Lezione 6 del Kit Kuman: quella proposta non mi piace, la trovo poco chiara e ho preferito realizzare la cosa a modo mio.

Prima di tutto, la distinta di quello che ci serve:

Assembly List

Label Part Type Properties
Componente1 Arduino Uno (Rev3) tipo Arduino UNO (Rev3)
Disp1 LBT2088AH size 60.5mm; variant variant 1; part number LBT2088AH
R1 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R2 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R3 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R4 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R5 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R6 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R7 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R8 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
R9 10kΩ Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 10kΩ
S1 Pushbutton package [THT]

Shopping List

Amount Part Type Properties
1 Arduino Uno (Rev3) tipo Arduino UNO (Rev3)
1 LBT2088AH size 60.5mm; variant variant 1; part number LBT2088AH
8 220Ω Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 220Ω
1 10kΩ Resistor package THT; tolerance ±5%; bands 4; pin spacing 400 mil; resistenza 10kΩ
1 Pushbutton package [THT]

Dopodiché dobbiamo collegare il nostro Arduino alla matrice: qui trovate uno schema che spero sia comprensibile.

L’ho realizzato con TinkerCAD e, non essendo disponibile tra i componenti di libreria la 8×8 Dot Matrix (Codice: 1588BS), mi sono dovuto arrangiare ricostruendo la matrice di led (ben 64!) e relativo circuito.

Ci credete se vi dico che ci ho preso al primo colpo ? Ok, non ci credevo nemmeno io !

Purtroppo, simulando, i LED sono abbastanza scuri e non si capisce bene ma, aprendo la console di output, è possibile vedere l’output che ho previsto e che rappresenta “con i caratteri” quello che viene visualizzato sui LED e risulta tutto più semplice.

Come si può notare dalla foto, lo schema non combacia per nulla, quindi, mi sono preso pure la briga di implementarne uno più fedele tramite un software open-source che ho trovato (che ha numerosissimi componenti): Fritzing.

Schema della Lezione 6 del Kit Kuman Arduino UNO r3

 

 

 

 

 

Nel caso in cui neanche questo sia chiaro, ci provo con lo schema elettrico:

Schema Elettrico Lezione 6 Kit Kuman Arduino UNO r3

Quello che segue è il codice (che potete scaricare anche cliccando qui, così da non perdere la formattazione) autoesplicativo (nel senso che l’ho commentato parecchio):

/*

Nel KIT Kuman Arduino UNO r3 è inclusa una 8x8 Dot Matrix Cod.: 1588BS

Possiede 8+8 pin che, visti da sopra (cioè guardando i LED e immaginando i
piedini sotto, dato che non sono visibili) e numerati in senso antiorario,
sono così disposti:

16 15 14 13 12 11 10 9
- - + - + - - +

+ + - - + - + +
1 2 3 4 5 6 7 8

+ = Anodo

- = Catodo

Quando si collegano i PIN della Matrice a quelli di Ardiono è opportuno
prevedere una resistenza, su ogni catodo, da 220 Ohm.

I PIN della Matrice vanno a pilotare RIGHE e COLONNE secondo il seguente
schema:

- - - - - - - - -> CATODO
13 3 4 10 6 11 15 16 -> PIN
1 2 3 4 5 6 7 8 -> COLONNA
+ 9 1 O O O O O O O O
+ 14 2 O O O O O O O O
+ 8 3 O O O O O O O O
+ 12 4 O O O O O O O O
+ 1 5 O O O O O O O O
+ 7 6 O O O O O O O O
+ 2 7 O O O O O O O O
+ 5 8 O O O O O O O O
| | |
| | |_> RIGA
| |___> PIN
|______> ANODO

Volendo mettere in ordine di PIN della Matrice si ottiene:

- - - - - - - - -> CATODO
3 4 6 10 11 13 15 16 -> PIN
2 3 5 4 6 1 7 8 -> COLONNA
+ 1 5 O O O O O O O O
+ 2 7 O O O O O O O O
+ 5 8 O O O O O O O O
+ 7 6 O O O O O O O O
+ 8 3 O O O O O O O O
+ 9 1 O O O O O O O O
+ 12 4 O O O O O O O O
+ 14 2 O O O O O O O O
| | |
| | |_> RIGA
| |___> PIN
|______> ANODO

Dato che nell'Ardiono:

- Esistono 13 PIN Digitali
- I primi due PIN (0 e 1) non sono utilizzabili (sono usati per RX e TX)

Non è possibile associare direttamente ogni PIN della Matrice ad uno
corrispondente dell'Arduino.
Per ovviare al problema bisogna:

1) Utilizzare i PIN Digitali dal 2 al 13 (per un totale di 12 PIN)
2) Utilizzare i PIN Analogici da A0 ad A3 (per un totale di 4 PIN)

in modo da avere un totale di 16 PIN di comando.

Comandare l'accensione delle RIGHE e' semplice perché sufficiente mettere ad
HIGH il PIN relativo alla riga da illuminare; ad esempio, volendo accendere la
riga 5, bisogna mettere in HIGH il PIN 1 della matrice.

Viceversa, l'accensione delle COLONNE, risulta complicata perché bisogna
eseguire 2 operazioni:

1) Accendere tutte le RIGHE mettendole in HIGH.
2) Spegnere tutte le COLONNE mettendole in HIGH (sì, il contrario) tranne
quella desiderata, che va messa in LOW.

La visualizzazione di caratteri poi è ulteriormente complicata dal fatto che
non è possibile decidere quali punti della matrice lasciare accesi e quali
spenti contemporaneamente, semplicemente intervenendo sui PIN.

Lo stratagemma utilizzato prevede di sfruttare alcune caratteristiche:

1) La velocità di Arduino nell'eseguire le operazioni.
2) La lentezza dell'occhio umano nel percepire quando un LED viene spento
3) La "persistenza luminosa" di un LED anche dopo che è stato spento.

Operando in questo modo è possibile dare l'illusione che i LED della matrice
siano contemporaneamente accesi, anche se questo non è vero praticamente.

********************************************************************************
*/

#define PIN_MIN 1
#define PIN_MAX 16

#define MAX_INT 32768

/* Numero di "ripetizioni" del carattere affinche' risulti visibile. */
#define REPEAT_CHAR 128

/* Tempo di attesa quando viene premuto il pulsante. */
#define DEFAULT_DELAY 1000

/* Corrispondenza PIN Analogici: Nome PIN -> Valore Numerico
* A0 -> 14
* A1 -> 15
* A2 -> 16
* A3 -> 17
* A4 -> 18 (non usato)
* A5 -> 19 (non usato)
*
*/

const long clTimerPause = 10000; // Pausa quando viene premuto il pulsante

/* Array contenente l'Associazione PIN Matrice -> PIN Arduino
* Il primo valore dell'Array (0) non va considerato, serve solo affinché al
* PIN 1 della Matrice corrisponda il PIN A3 di Arduino e così via fino al
* PIN 16 della Matrice che corrisponde il PIN 13 di Arduino.
*
* L'associazione di questo Array può essere usata per eseguire in modo
* relativamente facile il collegamento tra Arduino e la Matrice.
*
*/
const int ciMatrix_Arduino[] = {0,
A3, A1, 7, 8, A0, 10, A2, 4, 2, 9, 11, 5, 6, 3, 12, 13};
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 -> Matrice

/* Array contenente l'Associazione PIN Arduino -> PIN Matrice */
const int ciArduino_Matrix[] = {0, 1,
9, 14, 8, 12, 13, 3, 4, 10, 6, 11, 15, 16, 5, 2, 7, 1};
// 2 3 4 5 6 7 8 9 10 11 12 13 A0 A1 A2 A3 -> Arduino

/* Una matrice di corrispondenza per le RIGHE. */
const int ciRow[] = {0,
2, 3, 4, 5, A3, A2, A1, A0}; // -> PIN ARDUINO
// 1 2 3 4 5 6 7 8 -> RIGA MATRICE
// 9 14 8 12 1 7 2 5 -> PIN MATRICE

/* Una matrice di corrispondenza per le COLONNE. */
const int ciCol[] = {0,
6, 7, 8, 9, 10, 11, 12, 13}; // -> PIN ARDUINO
// 1 2 3 4 5 6 7 8 -> COLONNA MATRICE
//13 3 4 10 6 11 15 16 -> PIN MATRICE

/* Dichiara un array di array contenente una mappa di font unicode 8x8 */
unsigned char font8x8_basic[128][8] = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) 0
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A 10
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 20
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E 30
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
{ 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
{ 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
{ 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
{ 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
{ 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
{ 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
{ 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
{ 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() 40
{ 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
{ 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
{ 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
{ 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
{ 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
{ 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
{ 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
{ 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) 50
{ 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
{ 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
{ 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
{ 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
{ 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
{ 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
{ 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
{ 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (//)
{ 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) 60
{ 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
{ 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
{ 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
{ 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
{ 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
{ 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
{ 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
{ 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
{ 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) 70
{ 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
{ 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
{ 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
{ 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
{ 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
{ 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
{ 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
{ 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
{ 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
{ 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) 80
{ 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
{ 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
{ 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
{ 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
{ 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
{ 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
{ 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
{ 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
{ 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) 90
{ 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
{ 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
{ 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
{ 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
{ 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
{ 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
{ 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
{ 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
{ 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) 100
{ 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
{ 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
{ 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
{ 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
{ 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
{ 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
{ 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
{ 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
{ 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) 110
{ 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
{ 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
{ 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
{ 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
{ 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
{ 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
{ 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
{ 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) 120
{ 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
{ 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
{ 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
{ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
{ 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
{ 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F 127
};

/*
* Per capire come funziona l'array cui sopra, basta prendere la definizione
* di un carattere, la "A" (ad esempio) e convertire i valori esadecimali in
* valori binari a 8 bit:
*
* { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
*
* 0x0C = 0 0 0 0 1 1 0 0
* 0x1E = 0 0 0 1 1 1 1 0
* 0x33 = 0 0 1 1 0 0 1 1
* 0x33 = 0 0 1 1 0 0 1 1
* 0x3F = 0 0 1 1 1 1 1 1
* 0x33 = 0 0 1 1 0 0 1 1
* 0x33 = 0 0 1 1 0 0 1 1
* 0x00 = 0 0 0 0 0 0 0 0
*
* Dopodichè lo 0 è uno spazio (LED spento) e 1 un punto (LED acceso); così
* si capisce meglio:
*
* 0x0C = X X
* 0x1E = X X X X
* 0x33 = X X X X
* 0x33 = X X X X
* 0x3F = X X X X X X
* 0x33 = X X X X
* 0x33 = X X X X
* 0x00 =
*
*/

/*
********************************************************************************
* Vengono definite alcune funzioni che possono risultare utili per operare sulla
* matrice.
********************************************************************************
*/
/*
********************************************************************************
* Accende tutte le righe.
*/
void SetHighAllRows() {
for (int i = 1; i <= 8; i++) {
digitalWrite(ciRow[i], HIGH);
}
}

/*
********************************************************************************
* Spegne tutte le righe.
*/
void SetLowAllRows() {
for (int i = 1; i <= 8; i++) {
digitalWrite(ciRow[i], LOW);
}
}

/*
********************************************************************************
* Spegne tutte le colonne usando "iExclude" uguale a 0.
* Se ha un valore diverso da 0, la relativa colonna, non viene spenta.
*/
void SetHighAllCols(int iExclude = 0) {
for (int i = 1; i <= 8; i++) {
if (!iExclude || iExclude != i)
digitalWrite(ciCol[i], HIGH);
}
}

/*
********************************************************************************
* Accende tutte le colonne usando "iExclude" uguale a 0.
* Se ha un valore diverso da 0, la relativa colonna, non viene accesa.
*/
void SetLowAllCols(int iExclude = 0) {
for (int i = 1; i <= 8; i++) {
if (!iExclude || iExclude != i)
digitalWrite(ciCol[i], LOW);
}
}

/*
********************************************************************************
* Esegue una pausa mentre controlla che non sia stato premuto il pulsante.
* Se e' stato premuto, la pause viene prolungata al valore impostato.
*/
void CheckPause() {
int iReadButton = analogRead(A5);

while (iReadButton > 0) {
Serial.print("PAUSA di " + String(clTimerPause / 1000) + " secondi....");
delay(clTimerPause);
Serial.println(" finita, si riparte !");
iReadButton = analogRead(A5);
}

delay(DEFAULT_DELAY);
}

/*
********************************************************************************
* Accende o Spegne un singolo LED della matrice, in base alla riga, colonna e il
* flag booleano.
*/
void DisplayPixel(int iRow, int iCol, bool bShow = true) {
if (bShow == true) {
digitalWrite(ciRow[iRow], HIGH);
SetHighAllCols(iCol);
} else {
digitalWrite(ciRow[iRow], LOW);
SetLowAllCols(iCol);
}
}

/*
********************************************************************************
* Visualizza un singolo carattere, passato come parametro e formato da una
* matrice di 8 x 8 bit.
*/
void RenderChar(unsigned char *bitmap) {
int iMask = 0; // Numero utilizzato come flag
bool bShowRow = false; // Booleano che determina se la riga deve essere accesa

for (int r = 0; r < 8; r++) { // Esegue un ciclo per ogni riga
for (int c = 0; c < 8; c++) { // Esegue un ciclo per ogni colonna
/* Lo scopo è quello di determinare se la colonna presa in esame deve
* essere accesa.
*
* bitmap[r] contiene il byte che rappresenta la riga "r" del carattere
* da visualizzare, composto da un numero binario a 8 bit.
* Questi 8 bit vengono "spostati verso destra" della quantità "c" che,
* inizialmente, vale 0 (quindi nessun spostamento all'inizio).
* Dopodiché viene eseguita un'operazione logica AND (&) con il valore
* esadecimale 0x1 che corrisponde a 1 decimale e 00000001 in binario.
*
* Dato che l'operatore AND lavora in questo modo (sui numeri binari):
* 0 & 0 = 0
* 1 & 0 = 0
* 1 & 1 = 1
*
* il numero binario rappresentato da bitmap[r] farà quindi assumere
* alla variabile iMask il valore 0 se l'ultimo bit è 0 e 1 se l'ultimo
* bit è 1.
*
* Ad esempio, se bitmap[r] vale "10010010" abbiamo che:
* 10010010 &
* 00000001 =
* 00000000
* Mentre se vale "10010011" abbiamo che:
* 10010011 &
* 00000001 =
* 00000001
*
* Lo spostamento binario tramite ">>" di "c" posti serve per analizzare
* tutti i bit delle 8 colonne della riga analizzata. "c" infatti varia da
* 0 a 7.
*
* Se, ad esempio, bitmap[r] vale "10010010", quando viene eseguito
* ">> 7" si ottiene "00000001" perché l' 1 che stava all'inizio è stato
* spostato 7 volte verso destra e i valori che c'erano prima rimpiazzati
* da 0.
*
*/
iMask = (bitmap[r] >> c)&(0x1);

if (iMask) {
Serial.print(" X ");
} else {
Serial.print(" ");
}
}
Serial.println("");
}
Serial.println("");

for (int t = 0; t < REPEAT_CHAR || analogRead(A5) > 0; t++) {
for (int r = 0; r < 8; r++) {
bShowRow = false;
SetLowAllRows(); // Tutte le righe spente
SetHighAllCols(); // Tutte le colonne "spente"

for (int c = 0; c < 8; c++) {
iMask = (bitmap[r] >> c)&(0x1);

if (iMask) { // Colonna da accendere
if (bShowRow == false) {
/* Nel momento in cui una colonna risulta da accendere,
* bisogna necessariamente accendere tutta la riga,
* che altrimenti resta spenta per migliorare la qualità
* del numero visualizzato.
*
*/
bShowRow = true;
digitalWrite(ciRow[r+1], HIGH);
}

digitalWrite(ciCol[c+1], LOW);
} else {
// Colonna da spegnere.
digitalWrite(ciCol[c+1], HIGH);
}
}
}

SetLowAllRows(); // Tutte le righe spente
SetHighAllCols(); // Tutte le colonne "spente"
}
}

/*
********************************************************************************
*/
void setup() {
// Inizializza le porte di output
for (int i = PIN_MIN; i <= PIN_MAX; i++) {
/* Imposta i vari PIN come output.
*/
pinMode(ciMatrix_Arduino[i], OUTPUT);
}
SetLowAllRows(); // Tutte le righe spente
SetHighAllCols(); // Tutte le colonne "spente"

Serial.begin(9600); // Inizializza la seriale
}

void loop() {
/* Crea una tabella di 94 caratteri contenente i caratteri ASCII che vanno
* dal codice 32 al 126.
*
* Per vedere la corrispondenza, fare affidamento alla dichiarazione della
* variabile array font8x8_basic .
*/
unsigned char *bitmap[95];
for (int l = 0; l < 94; l++) {
bitmap[l] = font8x8_basic[l + 32];
}
bitmap[94] = 0;

Serial.println("PARTENZA.");
/* Il ciclo è costruito per stampare al massimo MAX_INT caratteri e fermarsi
* quando incontra che "bitmap" vale 0.
*/
for (int i = 0; i < MAX_INT; i++) {
if (bitmap[i] == 0)
break;

// Visualizza il carattere.
RenderChar(bitmap[i]);
}

// Esegue una pausa prima di ripartire.
delay(DEFAULT_DELAY);
Serial.println("RESET: Si riparte !");
}

Infine il video che ho caricato su YouTube dove si vede tutto in funzione:

Spero che a qualcuno sia d’aiuto. Se avete dubbi, chiedete pure: sono un niubbo ma forse una mano riesco a darla.

 

Autore: BuDuS

Disegnatore Meccanico, con la passione per l'Informatica. Come hobby, produco piccoli software di (in)utilità.