LED-Matrix max7219

In diesem Wiki-Eintrag soll es im Gegensatz zum anderen LED-Matrix-Eintag, nicht um die selbstgebauten Matrizen, sondern um LED-Matrizen vom Typ max7219 gehen. Hier sind im Folgenden einige Code-Beispiele, um solche Matrizen mit dem Arduino zu bedienen, sowie das Anschließen an eben diesen zu finden.

Anschließen

Initialisierung im Arduino Code

Je nachdem, wie viele Matrizen man anschließen möchte, muss man ggf. die Variable 'maxInUse' auf die entsprechende Zahl anpassen.

// *****************   Beginn Initialisierung Matrix   ************************
 
int dataIn = 2;
int load = 3;
int clock = 4;
 
int maxInUse = 3;    //change this variable to set how many MAX7219's you'll use
 
// define max7219 registers
byte max7219_reg_noop        = 0x00;
byte max7219_reg_digit0      = 0x01;
byte max7219_reg_digit1      = 0x02;
byte max7219_reg_digit2      = 0x03;
byte max7219_reg_digit3      = 0x04;
byte max7219_reg_digit4      = 0x05;
byte max7219_reg_digit5      = 0x06;
byte max7219_reg_digit6      = 0x07;
byte max7219_reg_digit7      = 0x08;
byte max7219_reg_decodeMode  = 0x09;
byte max7219_reg_intensity   = 0x0a;
byte max7219_reg_scanLimit   = 0x0b;
byte max7219_reg_shutdown    = 0x0c;
byte max7219_reg_displayTest = 0x0f;
 
void putByte(byte data) {
  byte i = 8;
  byte mask;
  while (i > 0) {
    mask = 0x01 << (i - 1);      // get bitmask
    digitalWrite( clock, LOW);   // tick
    if (data & mask) {           // choose bit
      digitalWrite(dataIn, HIGH);// send 1
    } else {
      digitalWrite(dataIn, LOW); // send 0
    }
    digitalWrite(clock, HIGH);   // tock
    --i;                         // move to lesser bit
  }
}
 
void maxAll (byte reg, byte col) {    // initialize  all  MAX7219's in the system
  int c = 0;
  digitalWrite(load, LOW);  // begin
  for ( c = 1; c <= maxInUse; c++) {
    putByte(reg);  // specify register
    putByte(col);//((data & 0x01) * 256) + data >> 1); // put data
  }
  digitalWrite(load, LOW);
  digitalWrite(load, HIGH);
}
void maxOne(byte maxNr, byte reg, byte col) {    
//maxOne is for adressing different MAX7219's, 
//whilele having a couple of them cascaded
 
  int c = 0;
  digitalWrite(load, LOW);  // begin     
 
  for ( c = maxInUse; c > maxNr; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }
 
  putByte(reg);  // specify register
  putByte(col);//((data & 0x01) * 256) + data >> 1); // put data 
 
  for ( c =maxNr-1; c >= 1; c--) {
    putByte(0);    // means no operation
    putByte(0);    // means no operation
  }
 
  digitalWrite(load, LOW);
  digitalWrite(load,HIGH); 
}
 
void setup() {
 
  Serial.begin(9600);
 
  pinMode(dataIn, OUTPUT);
  pinMode(clock,  OUTPUT);
  pinMode(load,   OUTPUT);
 
  //initiation of the max 7219
  maxAll(max7219_reg_scanLimit, 0x07);
  maxAll(max7219_reg_decodeMode, 0x00);  // using an led matrix (not digits)
  maxAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
  maxAll(max7219_reg_displayTest, 0x00); // no display test
  for (int e = 1; e <= 8; e++) { // empty registers, turn all LEDs off
    maxAll(e, 0);
  }
  maxAll(max7219_reg_intensity, 0x0f & 0x0f);    // the first 0x0f is the value you can set
  // range: 0x00 to 0x0f
 
}
 
// *********************************   Ende Initialisierung Matrix   **********************************

Pong

Um ein Pongspiel mit zwei Spielern auf ebenfalls zwei Led-Matrizen zu realiesieren, die man mit zwei Tasten steuert, kann man hinter die Initialisierung nachfolgende Code-Zeilen setzen:

int zeit = 0;
 
  int Schlaegerrechts = 24;      // Schläger 1
  int Schlaegerlinks = 24;      // Schläger 2
 
  int taster1 = 5;      // Taster 1        1 und 2 für Schläger rechts
  int taster2 = 6;      // Taster 2
  int taster3 = 7;      // Taster 3        3 und 4 für Schläger links
  int taster4 = 8;      // Taster 4  
 
  int read_taster1;
  int read_taster2; 
  int read_taster3; 
  int read_taster4; 
 
  unsigned long time1 = 0;       
  unsigned long time2 = 0;
  unsigned long time3 = 0;
  unsigned long debounce = 100;
  unsigned long debounce2 = 10000;
 
  int matrix = 1;                    // Matrix auf der sich der Ball aktuell befindet
  int xball = 3;
  int dx = 1;                   // x-Richtung
  int yball = 1;
  float dy = 2.0;               // y-Richtung als float, da die Änderung teilweise 0,5 ist. Kommazahlen nicht als int
  int r = 0;                    // Variable für Zufallsgenerierung
  int vball = 25;               // Ballgeschwindigkeit
 
  int zahl[] = {nul, eins, zwei, drei, vier, fuenf, sechs, sieben, acht, neun};
  int xz = 0;                  // xz + den aktuelen Wert x ergibt zahl[] 
  int Wert1 = 0;               // Wert1 - Wert4 für den Punktestand der beiden Spieler --> pro Matrix (und Spieler) zwei Zahlen
  int Wert2 = 0;
  int Wert3 = 0;
  int Wert4 = 0;
 
 
void loop() {
 
  maxOne (2, 1, Schlaegerrechts);          // Position Schläger 1
  maxOne (1, 8, Schlaegerlinks);          // Position Schläger 2
  delay(2);
 
  // ******   Schläger   ******
 
  read_taster1 = digitalRead (taster1);
  read_taster2 = digitalRead (taster2);
  read_taster3 = digitalRead (taster3);
  read_taster4 = digitalRead (taster4);
 
  if (read_taster1 == HIGH && Schlaegerrechts >= 6 && millis() - time1 > debounce) {          // Bewegung Schläger über Taster
    time1 = millis();
    Schlaegerrechts = Schlaegerrechts /= 2;
  }
 
  if (read_taster2 == HIGH && Schlaegerrechts <= 96 && millis() - time1 > debounce) {         // Bewegung Schläger über Taster
    time1 = millis();
    Schlaegerrechts = Schlaegerrechts *= 2;
  }
 
  if (read_taster3 == HIGH && Schlaegerlinks >= 6 && millis() - time2 > debounce) {          // Bewegung Schläger über Taster
    time2 = millis();
    Schlaegerlinks = Schlaegerlinks /= 2;
  }
 
  if (read_taster4 == HIGH && Schlaegerlinks <= 96 && millis() - time2 > debounce) {         // Bewegung Schläger über Taster
    time2 = millis();
    Schlaegerlinks = Schlaegerlinks *= 2;
  }
 
  delay(1);
 
  // ******   Ball   ******
 
  r = random (0, 3);                                      // y-Richtung Ball ändert zufaällig am Schläger
                                                          // random zwischen 0-5 --> jeweils 2 random Werte stehen für ein dy --> Zuweisung dort, wo Schläger und Ball zusammentreffen
 
   if (millis() - time3 > debounce2 && vball > 3) {       // Änderung der Ballgeschwindigkeit --> wird immer schneller
      time3 = millis();
      vball--;
    }
 
  if (zeit == 0) {
 
    maxOne (matrix, xball, 0);                            // Null setzt die Spalte zurück, sodass der Ball immer ein Punkt bleibt
    xball += dx;                                     // Bewegung in x-Richtung
    yball *= dy;                                     // Bewegung in y-Richtung
 
    if (yball == 128) {                              // Ball am oberen Spielfeldrand
      dy = 0.5;
    }
 
    if (yball == 1) {                                // Ball am unteren Spielfeldrand
      dy = 2;
    }
 
    if (xball == 9 && matrix == 2 && dx == 1) {          // Ball am rechten Rand der linken Matrix
      matrix = 1;                                        // Ball springt auf die rechte Matrix
      xball = 1;                                    // x Komponente wieder 1, da rechte Matrix dort wieder bei 1 los geht
    }
 
    if (xball == 0 && matrix == 1&& dx == -1) {         // Ball am linken Rand der rechten Matrix
      matrix = 2;                                       // Ball springt auf die linke Matrix
      xball = 8;                                   // x Komponente 8, da linke Matrix dort wieder bei 8 anfängt
    }
 
    // ******   rechter Spielfeldrand   ******
 
    if (xball == 7 && matrix == 1) {
 
      int pos1 = Schlaegerlinks / 3;                                           // zur Ermittlung ob Schläger den Ball trifft
 
      if (yball == pos1 || yball == 2 * pos1) {                    // Schläger trifft
        dx = -1;
 
        if(r == 0 && yball != 1) {                     // Änderung der y-Richtung wird mit den folgenden 3 if-Schleifen bestimmt
          dy = 0.5;                                                
        }
        else if (r == 1) {
          dy = 1;
        }
        else if (r == 2 && yball != 128) {
          dy = 2;
        }
      }
      else {                                          // Schläger trifft nicht
 
        Wert2 = Wert2 + 4;                            // ab hier Punktezähler für den linken Spieler
        if (Wert2 == 40) {                            // Zahl immer plus 4, da jede Zahl vier Spalten belegt (siehe Buchstaben.h)
          Wert2 = 0;
          Wert1 = Wert1 + 4;
        }
        for (int a = 0; a < 4; a++) {
          xz = a + Wert1;
          maxOne (2, a + 1, zahl [xz]);
        }
        for (int a = 0; a < 4; a++) {
          xz = a + Wert2;
          maxOne (2, a + 5, zahl [xz]);
        }                                            // Ende Punkezähler linker Spieler
 
        for (int a = 0; a < 4; a++) {                // Analog dazu der Punktestand des anderen Spielers ; ändert sich nicht
          xz = a + Wert3;
          maxOne (1, a + 2, zahl [xz]);
        }
        for (int a = 0; a < 4; a++) {
          xz = a + Wert4;
          maxOne (1, a + 6, zahl [xz]);
        }
 
        delay(2000);
 
        for (int a = 1; a < 9; a++) {
          maxAll (a, 0);                            // Matrix zurücksetzen
        }
 
        xball = 3;                                  // Variablen zurücksetzen
        yball = 1;
        dx = 1;
        dy = 2;
        Schlaegerrechts = 24;
        Schlaegerlinks = 24;
        vball = 18;
      }
    }
 
    // ******   linker Spielfeldrand   ******
 
    if (xball == 2 && matrix == 2) {
 
     int pos2 = Schlaegerrechts / 3;                                              // zur Ermittlung ob Schläger den Ball trifft
      if (yball == pos2 || yball == 2 * pos2) {                      // Schläger trifft
        dx = 1;
 
        if(r == 0 && yball != 1) {                                   // Änderung der y-Richtung wird mit den folgenden 3 if-Schleifen bestimmt
          dy = 0.5;
        }
        else if (r == 1) {
          dy = 1;
        }
        else if (r == 2 && yball != 128) {
          dy = 2;
        }
      }
      else {                                                        // Schläger trifft nicht
 
        Wert4 = Wert4 + 4;                                          // ab hier Punktezähler für den rechten Spieler
        if (Wert4 == 40) {
          Wert4 = 0;
          Wert3 = Wert3 + 4;
        }
        for (int b = 0; b < 4; b++) {
          xz = b + Wert3;
          maxOne (1, b + 2, zahl [xz]);
        }
        for (int b = 0; b < 4; b++) {
          xz = b + Wert4;
          maxOne (1, b + 6, zahl [xz]);
        }                                                          // Ende Punktezähler rechter Spieler
 
        for (int b = 0; b < 4; b++) {                              // Analog der Punktestand des anderen Spielers ; ändert sich nicht
          xz = b + Wert1;
          maxOne (2, b + 1, zahl [xz]);
        }
        for (int b = 0; b < 4; b++) {
          xz = b + Wert2;
          maxOne (2, b + 5, zahl [xz]);
        }
 
        delay(2000);
 
        for (int b = 1; b < 9; b++) {
          maxAll (b, 0);                            // Matrix zurücksetzen
        }
        xball = 3;                                  // Variablen zurücksetzen
        yball = 1;
        dx = 1;
        dy = 2;
        Schlaegerrechts = 24;
        Schlaegerlinks = 24;
        matrix = 1;
        vball = 18;
      }
    }
 
    maxOne (matrix, xball, yball);        // Position Ball
  }
 
  zeit = (zeit + 1) % vball;         // Nach jedem dritten Durchgang wird die Schleife für den Ball ausgeführt
                                     // Modulo ist erforderlich, da mit einem längeren delay die Schläger langsamer wären
                                     // Duch das Modulo läuft der Ball unabhängig von den Schläger
 
 Serial.println(zeit);
 
 // ******   Spielende erreicht --> Spiel wird auf Null zurückgesetzt   ******
 
 if (Wert1 == 8 && Wert2 == 4 || Wert3 == 8 && Wert4 == 4) {                  // Puntestand von 21 ist Spiel gewonnen und startet von Vorne
 
   for (int c = 0; c < 9; c++) {
     maxAll (c, 0);
   }
 
   Wert1 = 0;
   Wert2 = 0;
   Wert3 = 0;
   Wert4 = 0;
 
   for (int c = 1; c < 9; c++) {
     maxOne (2, c, 255);
     maxOne (1, 9 - c, 255);
     delay(200);
     maxOne (2, c, 0);
     maxOne (1, 9 - c, 0);
   }
   for (int c = 0; c < 9; c++) {
     maxAll (c, 255);
   }
   delay (4000);
 
   for (int c = 0; c < 9; c++) {
     maxAll (c, 0);
   }
 
   vball = 25;                                      // Geschwindigkeit zurückstzen
 }
 
}

In diesem Codebeispiel sind die Zahlen der Spielstände in eine extra Header-Datei ausgelagert, um den Code übersichtlicher zu machen. Um eine Header-Datei im Code zu includieren fügt man als erste Zeile des Codes

#include "HeaderDateiName.h" 

ein.

Die Header-Datei hat in unserem Beispiel folgenden Inhalt:

 #define nul     127, 65, 127, 0       //4
 #define eins    0, 0, 127, 0          //4
 #define zwei    121, 73, 79, 0        //4
 #define drei    73, 73, 127, 0        //4
 #define vier    15, 8, 127, 0         //4
 #define fuenf   79, 73, 121, 0        //4
 #define sechs   127, 73, 121, 0       //4
 #define sieben  1, 1, 127, 0          //4
 #define acht    127, 73, 127, 0       //4
 #define neun    79, 73, 127, 0        //4

Anmerkung zur 0: Da null bereits durch die C++Syntax belegt ist, wurde hier statt dem Wort null, das Wort nul als Variable gesetzt.

Hinweis: Das Pongspiel lässt sich auch mit einem schöneren und kürzeren Code realisieren. Obiger Code wird daher demnächst noch ersetzt.

Laufschrift

Im Folgenden ist ein Code, der eine Laufschrift auf die Matrizen projizieren kann. Wie man diesen Anpassen kann, findet man dadrunter beschrieben. Vor diesem Code ist der Initialisierungscode einzufügen.

int txt = 6;
 
unsigned long prev = 0;
const long interval = 200;        //Durchlaufgeschwindigkeit                    
 
int z[] = {
           Initialisieren,
           R, A, T, S, G, Y, M, N, A, S, I, U, M, _,
           P, E, I, N, E
           };
 
int x = 119;          // Zustände in z[]   --- siehe Buchstaben.h
 
int h[] = {24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
 
 
void loop () {
 
  unsigned long cur = millis();
 
  if(cur - prev >= interval){
    for (int i = 0; i < 24; i++){
      h[i]++;
    }
    prev = cur;
  }
 
 for (int i = 0; i < 24; i++){
   if(h[i] == x){
     h[i] = 0;
   } 
 } 
 
  maxOne(1,8,z[h[0]]);
  maxOne(1,7,z[h[1]]);
  maxOne(1,6,z[h[2]]);
  maxOne(1,5,z[h[3]]);
  maxOne(1,4,z[h[4]]);
  maxOne(1,3,z[h[5]]);
  maxOne(1,2,z[h[6]]);
  maxOne(1,1,z[h[7]]);
  maxOne(2,8,z[h[8]]);
  maxOne(2,7,z[h[9]]);
  maxOne(2,6,z[h[10]]);
  maxOne(2,5,z[h[11]]);
  maxOne(2,4,z[h[12]]);
  maxOne(2,3,z[h[13]]);
  maxOne(2,2,z[h[14]]);
  maxOne(2,1,z[h[15]]);
  maxOne(3,8,z[h[16]]);
  maxOne(3,7,z[h[17]]);
  maxOne(3,6,z[h[18]]);
  maxOne(3,5,z[h[19]]);
  maxOne(3,4,z[h[20]]);
  maxOne(3,3,z[h[21]]);
  maxOne(3,2,z[h[22]]);
  maxOne(3,1,z[h[23]]);
 
}

Um eine eigene Schrift anzeigen zu lassen, ist lediglich notwendig in

int  z[] ={ Initialisieren,...}; 

hinter „Initialisieren“ die gewollten Buchstaben einzufügen. Anschließend muss die Länge der Nachricht in

 int x =...;

angepasst werden. Hierzu werden 32 Zeichen für die Initialisierung benötigt und die restlichen Zahlen, die noch drauf addiert werden sollen, ist die Anzahl der Zeichen der jeweiligen Buchstaben, bzw. die Zahl, die in der „Buchstaben.h“ Datei als Kommentar hinter dem jeweiligen Buchstaben finden lassen.
Bei Ratsgymnasium Peine ist daher der Wert 119.

Schließlich muss hier noch die Header-Datei „Buchstaben.h“ noch includiert werden.

#include "Buchstaben.h"

Damit der Compiler die Header-Datei finden kann, muss sie im gleichen Ordner gespeichert sein, wie das gesamte Projekt. Die Arduino-Entwicklungsumgebung hilft dabei, indem man im Fenster mit dem geöffneten Code einen Tab hinzufügt und diese Datei entsprechend „Buchstaben.h“ nennt und anschließen den zugehörigen Inhalt hinzufügt.
Der Inhalt dieser Datei ist folgender:

// Alphabet Definition
 
 #define A  126, 17, 17, 126, 0        //5
 #define B  127, 73, 73, 54, 0         //5
 #define C  62, 65, 65, 65, 0          //5
 #define D  127, 65, 65, 62, 0         //5
 #define E  127, 73, 73, 65, 0         //5
 #define F  127, 9, 9, 1, 0            //5
 #define G  62, 65, 81, 50, 0          //5
 #define H  127, 8, 8, 127, 0          //5
 #define I  65, 127, 65, 0             //4
 #define J  65, 65, 63, 0              //4
 #define K  127, 20, 34, 65, 0         //5
 #define L  127, 64, 64, 0             //4
 #define M  127, 2, 12, 2, 127, 0      //6
 #define N  127, 4, 8, 16, 127, 0      //6
 #define O  62, 65, 65, 62, 0          //5
 #define P  127, 9, 9, 6, 0            //5
 #define Q  62, 65, 81, 33, 94, 0      //6
 #define R  127, 25, 41, 70, 0         //5
 #define S  38, 73, 73, 50, 0          //5
 #define T  1, 1, 127, 1, 1, 0         //6
 #define U  63, 64, 64, 63, 0          //5
 #define V  31, 32, 64, 32, 31, 0      //6
 #define W  127, 32, 28, 32, 127, 0    //6
 #define X  99, 20, 8, 20 ,99, 0       //6
 #define Y  3, 4, 120, 4, 3, 0         //6
 #define Z  97, 81, 73, 69 ,67, 0      //6
 
 #define AK  32, 84, 84, 120, 0        //5
 #define BK  63, 72, 72, 48, 0         //5
 #define CK  48, 72, 72, 72, 0         //5
 #define DK  48, 72, 72, 127, 0        //5
 #define EK  56, 84, 84, 88, 0         //5
 #define FK  126, 9, 1, 0              //4
 #define GK  76, 146, 146, 124, 0      //5
 #define HK  127, 8, 8, 112, 0         //5
 #define IK  122, 0                    //2
 #define JK  64, 136, 122, 0           //4
 #define KK  127, 16, 40, 68, 0        //5
 #define LK  63, 64, 64, 0             //4
 #define MK  120, 8, 112, 8, 120, 0    //6
 #define NK  8, 112, 8, 8, 112, 0      //6
 #define OK  48, 72, 72, 48, 0         //5
 #define PK  252, 36, 36, 24, 0        //5                (Alternative: 248, 72, 72, 48, 0)
 #define QK  24, 36, 36, 252, 0        //5                (Alternative: 48, 72, 72, 248, 0)
 #define RK  8, 112, 8, 8, 0           //5
 #define SK  72, 84, 84, 36, 0         //5
 #define TK  8, 63, 72, 64, 0          //5
 #define UK  56, 64, 64, 56, 0         //5
 #define VK  24, 32, 64, 32, 24, 0     //6
 #define WK  56, 64, 48, 64, 56, 0     //6
 #define XK  72, 48, 48, 72, 0         //5
 #define YK  4, 8, 112, 8, 4, 0        //6                (Alternative: 24, 160, 160, 120, 0)
 #define ZK  72, 104, 88, 72, 0        //5
 
 #define nul     127, 65, 127, 0       //4
 #define eins    0, 0, 127, 0          //4
 #define zwei    121, 73, 79, 0        //4
 #define drei    73, 73, 127, 0        //4
 #define vier    15, 8, 127, 0         //4
 #define fuenf   79, 73, 121, 0        //4
 #define sechs   127, 73, 121, 0       //4
 #define sieben  1, 1, 127, 0          //4
 #define acht    127, 73, 127, 0       //4
 #define neun    79, 73, 127, 0        //4
 
 #define Fragezeichen    2, 1, 89, 6, 0  //5
 #define Ausrufezeichen  79, 0           //2
 #define Punkt           64, 0           //2
 #define Appostroph      5, 3, 0         //3
 #define Komma           160, 96, 0      //3
 #define _               0, 0            //2    (Leerzeichen)
 
 #define Plus    8, 8, 62, 8, 8, 0         //6
 #define Minus   8, 8, 8, 8, 8, 0          //6
 #define Mal     20, 8, 62, 8, 20, 0       //6
 #define Geteilt 32, 16, 8, 4, 2, 0        //6
 #define Gleich  20, 20, 20, 20, 20, 0     //6
 
 #define Initialisieren 0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0  //24        Pro Matrix 8x 0 dazu
 
 #define Herz  28, 62, 126, 252, 126, 62, 28, 0                           //8