Οι πίνακες LED είναι ολοκληρωμένες διατάξεις από LEDs τοποθετημένα σε γραμμές και στήλες, που μπορούν να χρησιμοποιηθούν για την εμφάνιση αριθμών, γραμμάτων και σχημάτων.
Οι διατάξεις LEDs έχουν πολλές εφαρμογές στον σημερινό κόσμο, κυρίως στην εμφάνιση κειμένου στις φωτεινές πινακίδες, εμφάνιση εικόνων σε διαφημιστικές επιγραφές, σε διατάξεις ψηφιακών ρολογιών και προβολή άλλων πληροφοριών καθώς και σε πολλές άλλες εφαρμογές.

Κυκλοφορούν σε διάφορα μεγέθη, αλλά το πιο συνηθισμένο μέγεθος, εκείνο που θα χρησιμοποιήσουμε στα έργα μας σε αυτόν τον ιστότοπο και συγκεκριμένα πίνακες με 8Χ8 LEDs, δηλαδή 64 LEDs διατεταγμένα σε 8 σειρές και 8 στήλες.
Αν κοιτάξουμε το διάγραμμα διασύνδεσης των LED στη διάταξη, μπορούμε να θεωρήσουμε ότι τα LEDs είναι διασυνδεδεμένα με ένα από τους τρόπους: είτε σαν κοινής ανόδου είτε σαν κοινής καθόδου.
Έτσι μπορούμε να κάνουμε την κατάλληλη συνδεσμολογία, της LED διάταξης, ανάλογα πως θέλουμε να λειτουργεί: σαν κοινής ανόδου ή κοινής καθόδου. Όταν λειτουργεί σαν κοινής ανόδου, οι άνοδοι μιας σειράς LEDs συνδέονται μαζί, ενώ όταν λειτουργεί σαν κοινής καθόδου οι κάθοδοι μιας στήλης LEDs συνδέονται μαζί.

Λειτουργία της διάταξης 8Χ8 LED
Δεν είναι δυνατό να ανάψουν ταυτόχρονα πολλαπλά LED σε διαφορετικές σειρές και στήλες και να παραμείνουν αναμμένα. Για να δημιουργηθεί το οπτικό αποτέλεσμα, για τα LED που επιθυμούμε να είναι αναμμένα ταυτόχρονα, χρησιμοποιείται η μέθοδος της επιμονής της όρασης.
Τα μάτια μας συγκρατούν μια αναλαμπή φωτός για περίπου 20ms. Έτσι, όταν αναβοσβήνουμε γρήγορα ένα φως με ρυθμό ίσο ή ταχύτερο από 1/20ms, φαίνεται ότι το φως δεν σβήνει ποτέ.
Με βάση αυτή την ιδέα, ο μικροελεγκτής ανάβει τα απαιτούμενα LED σε μια σειρά (ή στήλη) μια κάθε φορά, εναλλάσσοντας όλες τις σειρές (ή στήλες) με ρυθμό ταχύτερο από 1/20ms. Έτσι, το ανθρώπινο μάτι εξαπατάται ώστε να βλέπει ότι τα LEDs είναι αναμμένα ταυτόχρονα.
Χρήση του ολοκληρωμένου MAX7219 ή MAX7221 για τον έλεγχο της διάταξης LED.
Για να ελέγξουμε άμεσα την διάταξη 8Χ8 LED με έναν μικροελεγκτή, θα έπρεπε να συνδέσουμε κάθε σειρά και κάθε στήλη σε pins, δηλαδή σε συνολικά 16 pins I/O του μικροελεγκτή. Αυτός ο μεγάλος αριθμός pins μαζί με τον σύνθετο κώδικα που θα πρέπει να γράψουμε, δεν είναι βολικός στην ανάπτυξη του έργου μας. Η λύση είναι η χρήση του ολοκληρωμένου κυκλώματος ΜΑΧ7219 ή του MAX7221 που μπορεί να οδηγήσει τα 64 LED χρησιμοποιώντας μόνο 3 αγωγούς για την σύνδεση του οδηγού με τον μικροελεγκτή.
Επιπλέον, μπορούμε να συνδέσουμε σε διάταξη αλυσίδας πολλαπλά ολοκληρωμένα MAX7219 (ή MAX7221) για μεγαλύτερα σύνολα, χωρίς να απαιτούνται επιπλέον pins.
Το MAX7219 καθώς και το ΜΑΧ7221 είναι ένα ολοκληρωμένο κύκλωμα με 24 pins, σχεδιασμένο ως σειριακός οδηγός κοινής καθόδου, που χρησιμοποιείται για την διασύνδεση μικροελεγκτών με LED οθόνες 7 τμημάτων έως 8 ψηφίων, γραφικές μπάρες ή 64 ανεξάρτητα LEDs. Στην περίπτωση μας, το χρησιμοποιούμε για τον έλεγχο της διάταξης 8Χ8 LEDs.
Ο οδηγός display MAX7221 είναι συμβατός με το πρωτόκολλο επικοινωνίας SPI το οποίο έχει ένα όριο στην ταχύτητα μεταφοράς δεδομένων για την μείωση της ηλεκτρομαγνητικής εκπομπής (ΕΜΙ). Ο οδηγός MAX7219 χρησιμοποιεί το δικό του σειριακό πρωτόκολλο, πανομοιότυπο με εκείνο του MAX7221.
Παρουσίαση του έργου μας
Σε αυτό το άρθρο παρουσιάζεται ένα shield για το Arduino Uno, το οποίο έχει ενσωματωμένο ένα 8Χ8 led dot matrix, που οδηγείται από το ολοκληρωμένο κύκλωμα οδηγό τύπου MAX7219 ή MAX7221.
Και οι δυο αυτοί οδηγοί MAX7219 και MAX7221 μπορούν να χρησιμοποιηθούν στο PCB με την ίδια συνδεσμολογία. Έτσι το έργο μας αναπτύσσεται σε δυο παραλλαγές με καθένα από αυτούς τους οδηγούς.

Το σχηματικό διάγραμμα σχεδιάστηκε με λογισμικό προσωπικού υπολογιστή και συγκεκριμένα με το eagle v9.4. Το κύκλωμα του dot matrix shield παρουσιάζεται στην παραπάνω εικόνα.
Το τυπωμένο κύκλωμα PCB παράγεται από το ίδιο λογισμικό, με μια φωτογραφία του όπως φαίνεται στην ακόλουθη εικόνα:

Κατασκευή
Η κατασκευή βασίζεται στην συναρμολόγηση των εξαρτημάτων πάνω στο τυπωμένο κύκλωμα. Η κατασκευή δεν παρουσιάζει ιδιαίτερη διαδικασία μιας που χρησιμοποιούνται σχετικά λίγα εξαρτήματα. Προσοχή πρέπει να δώσουμε στη σωστή τοποθέτηση του ολοκληρωμένου κυκλώματος και του 8Χ8 dot display. Για τη σωστή τοποθέτηση του ολοκληρωμένου κυκλώματος οδηγείται από μια εγκοπή στην μια άκρη του, ενώ για το dot display η αρίθμηση των ακρωδεκτών φαίνεται στην ακόλουθη εικόνα:

Πρώτη παραλλαγή
Στην πρώτη παραλλαγή χρησιμοποιούμε τον οδηγό MAX7219 ο οποίος χρησιμοποιεί το δικό του σειριακό πρωτόκολλο επικοινωνίας. Tο προβαλλόμενο μήνυμα εμφανίζεται χαρακτήρα – χαρακτήρα κάθε φορά πάνω στην διάταξη των 8Χ8 LEDs.
Το αντίστοιχο sketch αυτής της εφαρμογής ακολουθεί:
// Προβολή κειμένου χαρακτήρα - χαρακτήρα κάθε φορά
// Χρήση του ολοκληρωμένου κυκλώματος MAX7219 σαν οδηγό display
// Χρησιμοποιείται το συνηθισμένο σειριακό πρωτόκολλο επικοινωνίας του οδηγού //με το Arduino
#define DIN 11 // οι ακροδέκτες DIN, LOAD και CLK του MAX7219
#define LOAD 7 // δυνδέοντιαι με τα αντίστοιχα pin 11, 7 και 13 του Arduino
#define CLK 13
const byte letters[][5] = { // ορισμός δισδιάστατου πίνακα για τον
// προσδιορισμό των dots των χαρακτήρων που
// χρησιμοποιούνται στην ακεικόνιση του
//μηνύματος
{31,36,68,36,31}, //A
{127,73,73,73,54}, //B
{62,65,65,65,34}, //C
{127,65,65,34,28}, //D
{127,73,73,73,65}, //E
{127,72,72,72,64}, //F
{62,65,65,73,46}, //G
{127,8,8,8,127}, //H
{0,65,127,65,0}, //I
{2,1,1,1, 126}, //J
{127,8, 20,34,65}, //K
{127,1,1,1,1}, //L
{127,32,16,32,127}, //M
{127,32,16,8,127}, //N
{62,65,65,65,62}, //O
{127,72,72,72,48}, //P
{62,65,69,67,63}, //Q
{127,72,76,74,49}, //R
{48,73,73,73,6}, //S
{64,64,127,64,64}, //T
{126,1,1,1,126}, //U
{124,2,1,2,124}, //V
{127,2,4,2,127}, //W
{99,20,8,20,99}, //X
{64,32,31,32,64}, //Y
{67,69,73,81,97}, //Z
{62,65,65,65,62}, //0
{0,32,127,0,0}, //1
{79,73,73,73,121}, //2
{73,73,73,73,127}, //3
{120,8,8,8,127}, //4
{121,73,73,73,79}, //5
{127,73,73,73,79}, //6
{64,64,64,64,127}, //7
{127,73,73,73,127}, //8
{121,73,73,73,127}, //9
{0,0,0,0,0}, //' '
{0,0,121,0,0}, //!
{32,64,69,72,48} //?
};
byte len; // δήλωση του αριθμού των χαρακτήρων του προβαλόμενου μυνήματος.
char line[] = "MY NAME IS ARDUINO"; // το προβαλόμενο μήνυμα
char c, ch;
// συνάρτηση που στέλνει διδοχικά την address και value του υπο προσπελαση
// καταχωρητή
void max7219Transfer(unsigned char address, unsigned char value){
digitalWrite(LOAD, LOW);
shiftOut(DIN, CLK, MSBFIRST, address);
shiftOut(DIN, CLK, MSBFIRST, value);
digitalWrite(LOAD, HIGH);
delay(1);
}
void setup() {
pinMode(DIN, OUTPUT); // ορισμός των DIN, CLK, LOAD σαν έξοδοι
pinMode(CLK, OUTPUT);
pinMode(LOAD, OUTPUT);
digitalWrite(LOAD, HIGH);
digitalWrite(DIN, LOW); // θέτουμε τα DIN, CLK σε κατάσταση LOW
digitalWrite(CLK, LOW);
max7219Transfer(0x0F, 0x01); //Display – Test Register Format: Ανάβει όλα
//τα dots για έλεγχο
delay(2000);
max7219Transfer(0x0F, 0x00); //Display – Test Register Format: Επιστροφή
//σε κανονική λειτουργία
max7219Transfer(0x09, 0x00); //Decode – Mode Register Format: Μη BCD
//κωδικοποίηση για τα ψηφία 7-0
max7219Transfer(0x0C, 0x01); //Shutdown Register Format: Λειτουργία σε μη
//αναμονή
max7219Transfer(0x0B, 0x07); // Scan – Limit Register Format: Χρήση των
//ψηφίων 01234567
for(byte j=1; j<=8; j++) max7219Transfer(j, 0); // σβήσιμο (μηδενισμός)
//όλων των dots του display
len = strlen(line); // μηκος σε χαρακτήρες του προβαλόμενου μηνύματος
}
void loop() {
for(byte m=0; m<len; m++){ //σάρωση όλων των χαρακτήρων του μηνύματος
ch=line[m]; //προσδιορισμός του χαρακτήρα στη θέση m του μηνύματος
if(ch>='A' && ch<='Z') c=ch-'A'; //αντιστοίχηση αυτού του χαρακτήρα στη θέση c του πινακα letters[][]
else if(ch>='0' && ch<='9') c=26+(ch-'0');
else if(ch==' ') c=36;
else if(ch=='!') c=37;
else c=38;
for(byte n=0; n<=4; n++){ // προβολή στο display του χαρακτήρα
// ο οποίος βρίσκεται στη θέση c τον πίνακα letters[][]
max7219Transfer(n+2, letters[c][n]);
}
delay(500);
}
for(byte j=1; j<=8; j++) max7219Transfer(j, 0);
// σβήσιμο και παύση για 2 δευτερόλεπτα
delay(2000);
}
Δεύτερη παραλλαγή
Στη δεύτερη παραλλαγή χρησιμοποιούμε τον οδηγό MAX7221 ο οποίος χρησιμοποιεί το πρωτόκολλο επικοινωνίας SPI και το προβαλλόμενο μήνυμα εμφανίζεται κυλιόμενο πάνω στην ίδια διάταξη.

Το αντίστοιχο sketch αυτής της εφαρμογής ακολουθεί:
// Προβολή κειμένου σε κύλιση
// Χρήση του ολοκληρωμένου κυκλώματος MAX7221 σαν οδηγό display
// Χρησιμοποιείται το σειριακό πρωτόκολλο επικοινωνίας SPI
// του οδηγού με το Arduino
#include <SPI.h> // συμπερίληψη της βιβλιοθηκης SPI.h για την σειριακή επικοινωνία
#include <avr/pgmspace.h> //συμπερίληψη της κατάλληλης βιβλιοθήκης για
//διάβασμα δεδομένων από μνημη προγράμματος
#define CS_PIN 7
const byte letters[] PROGMEM = // ορισμός δισδιάστατου πίνακα και
// εκχώριση του στη μνήμη προγράμματος
// για τον προσδιορισμό των dots των
// χαρακτήρων που χρησιμοποιούνται στην
// ακεικόνιση του μηνύματος
{31,36,68,36,31, //A
127,73,73,73,54, //B
62,65,65,65,34, //C
127,65,65,34,28, //D
127,73,73,73,65, //E
127,72,72,72,64, //F
62,65,65,73,46, //G
127,8,8,8,127, //H
0,65,127,65,0, //I
2,1,1,1, 126, //J
127,8, 20,34,65, //K
127,1,1,1,1, //L
127,32,16,32,127, //M
127,32,16,8,127, //N
62,65,65,65,62, //O
127,72,72,72,48, //P
62,65,69,67,63, //Q
127,72,76,74,49, //R
49,73,73,73,70, //S
64,64,127,64,64, //T
126,1,1,1,126, //U
124,2,1,2,124, //V
127,2,4,2,127, //W
99,20,8,20,99, //X
64,32,31,32,64, //Y
67,69,73,81,97, //Z
62,65,65,65,62, //0
0,32,127,0,0, //1
79,73,73,73,121, //2
73,73,73,73,127, //3
120,8,8,8,127, //4
121,73,73,73,79, //5
127,73,73,73,79, //6
64,64,64,64,127, //7
127,73,73,73,127, //8
121,73,73,73,127, //9
0,0,0,0,0, //' '
0,0,121,0,0, //!
32,64,69,72,48 //?
};
byte matrix[300]; // πίνακας για τον προσδιορισμό όλων των dots του μυνήματος
byte len; // δήλωση μεταβλητής για την εκχώρηση του μήκους του
// μυνήματος σε χαρακτήρες
char line[] = "?HELLO WORLD!"; // το προβαλόμενο μήνυμα
// συνάρτηση που στέλνει διδοχικά την address και value του υπο προσπελαση
// καταχωρητή χρησιμοποιώντας τις κατάλληλες συναρτήσεις της βιβλιοθήκης SPI
void max7221Transfer(unsigned char address, unsigned char value){
digitalWrite(CS_PIN, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(CS_PIN, HIGH);
delay(1);
}
void setup() {
SPI.begin(); // αρχικοποίηση της SPI επικοινωνίας
pinMode(CS_PIN, OUTPUT); // ορισμός του CS_PIN σαν έξοδο
digitalWrite(CS_PIN, HIGH); // θέσε την έξοδο CS_PIN σαν HIGH
SPI.setBitOrder(MSBFIRST);
//SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setDataMode(SPI_MODE0);
max7221Transfer(0x0F, 0x01); //Display – Test Register Format:
//Ανάβει όλα τα dots για έλεγχο
delay(2000);
max7221Transfer(0x0F, 0x00); //Display – Test Register Format:
//Επιστροφή σε κανονική λειτουργία
max7221Transfer(0x09, 0x00); //Decode – Mode Register Format:
//Μη BCD κωδικοποίηση για τα ψηφία 7-0
max7221Transfer(0x0C, 0x01); //Shutdown Register Format:
//Λειτουργία σε μη αναμονή
max7221Transfer(0x0B, 0x07); //Scan – Limit Register Format:
//Χρήση των ψηφίων 01234567
char c, ch;
len = strlen(line); // μηκος σε χαρακτήρες του προβαλόμενου μηνύματος
for(byte m=0; m<len; m++){ //σάρωση όλων των χαρακτήρων του μηνύματος
ch=line[m]; //προσδιορισμός του χαρακτήρα στη θέση m του μηνύματος
if(ch>='A' && ch<='Z') c=ch-'A';
else if(ch>='0' && ch<='9') c=26+(ch-'0');
else if(ch==' ') c=36;
else if(ch=='!') c=37;
else c=38;
for(byte n=0; n<=4; n++){
// δημιουργία του πίνακα matrix[] με τον ορισμό όλων των dots
//του μηνύματος στο display
matrix[(m+1)*6+n] = pgm_read_byte_near(letters+c*5+n);
}
matrix[(m+1)*6+5]=0; // εκχώρηση μιας μηδενικής στήλης dots μεταξύ των
//χαρακτήρων
}
}
void loop() {
// προβολή του κυλιόμενου μηνύματος στο dot matrix display
for(byte j=0; j<(len+1)*6; j++){
for(byte i=0; i<8; i++)
max7221Transfer(i+1, matrix[j+i]);
delay(200);
}
}