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.
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 **********************************
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.
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