2019-03-03
Végre nekem is sikerült legyűrnöm a MAX7219/7221-re épülő mátrix kijelzőt. Azért írom ezt, mert a neten számos írást találtok azoktól, akik már elöttem ezt megcselekedték. És ez jó, mert sok segítséget találtam a témában. A rossz, hogy kíváncsi természetem van, gyerekoromban is szétszedtem a játékaimat... Szóval több library-t letöltöttem az Aarduino/MAX72xx-hoz, és persze tele voltak bug-okkal, amire ugye manapság azt mondják, még nincs optimalzálva. Írtam egy sajátot, saját bug-okkal :).
A display 4 db 8 x 8 LED-es kijelző mátrixot tartalmaz, amiket egyenként egy-egy MAX7219 chip hajt meg, mivel egy chip 8 x 8 LED-et képes kezelni.
Egyébként nagyon kényelmes dolgunk van, egy SPI soros vonalon kiküldjük az utasításainkat a chipeknek. A chipek sorba vannak kötve (kaszkádolva), mindegyikben van egy 16 bit-es léptető regiszter, ezek tulajdonképpen egymás után vannak kötve.
Az adatainkat szép sorba kiléptetjük, és azok előszőr belépkednek az első chipbe, azután onnan a másodikba... úgy is elképzelhetjük, hogy 4 chip esetében egy szép hosszú 64 bites léptető regisztert kell feltöltenünk bitekkel.
A chip a kapott 16 bitnek az első 8 bitjét utasításként értelmezi, a másodikat pedig adatként. Ezeket a MAX7221 doksija részletezi. Soronként fel lehet tölteni az LED-eket, be lehet kapcsolni a chip-et, beállíthatjuk a fényerőt, vagy éppen stand by-ba lehet küldeni. Az Arduinot AVR oldalról nézve, az Atmel egy SPI interface-t épített a mikrovezérlőibe, amin keresztül a programozásuk is zajlik. A vezérlő amelyik chippel kommunikálni akar, annak CS (chip select) lábát 0-ba teszi. Szóval csak a CS lábat választhatjuk meg szabadon, a DIN (Data Input) és a CLK (Clock) lábakat attól függően kell bekötnünk, milyen Arduinot akarunk használni. A LED-ek kezeléséhez csináltam egy leds[] buffer memória tömböt, készítettem egy kis térképet, hol található ebben az egyes LED-ek. Azután megtaláljuk az alábbi header file-ban parancsok kódjait is. Azután látható, milyen parancsokat írtam a display kezeléséhez.
/******************************************************************************
* Author - Kiraly Tibor
* http://www.tkiraaly.hu
* Date - 2019.03.03.
* Chip - Ardiono, MAX7221 matrix display
* Compiler - Arduino IDE
*
* MAX7221 matrix display kezelese
*
*******************************************************************************
* Connect pins:
* Y
* MAX7221 display Uno Mega Nano
*
* DIN - MISO 12 50 D12
* CLK - SS (CLK) 10 52 D10
*
*******************************************************************************
* MAX7221 display memory map:
* Y
* +--------+--------+--------+--------+
* | 7 | 15 | 23 | 31 | 7
* +-----+ | 6
* | VCC | | 5
* | GND | | 4
* | DIN | | 3
* | CS | 2 | 2
* | CLK | 1 | 1
* +-----+ 0 | 8 | 16 | 24 | 0
* +--------+--------+--------+--------+
* X 01234567 8...
*
*******************************************************************************/
#ifndef KT_MAX7221M_H
#define KT_MAX7221M_H
#include <Arduino.h>
#define MAX7221_NOOP 0 // commands for MAX7221
#define MAX7221_DECODEMODE 9
#define MAX7221_INTENSITY 10
#define MAX7221_SCANLIMIT 11
#define MAX7221_SHUTDOWN 12
#define MAX7221_DISPLAYTEST 15
#ifndef MAX7221_CHIPS
#define MAX7221_CHIPS 4 // number of MAX7221 chips
#endif
#ifndef MAX7221_DIN
#define MAX7221_DIN 12 // NANO MISO
#endif
#ifndef MAX7221_CLK
#define MAX7221_CLK 10 // NANO SS (CLK)
#endif
#define MIN( a, b) (((a)>(b))?(b):(a))
#define MAX( a, b) (((a)>(b))?(a):(b))
class max7221m
{
private :
int cs_pin; // display select pin
public:
byte leds[ MAX7221_CHIPS * 8]; // LEDs buffer
max7221m( byte cs); // constructor
void send_cmd( byte target_chip, byte cmd, byte data= 0); // send command to chip
void send_all( byte opcode, byte data= 0); // send command to all chips
void bright( byte intensity)
{ send_all( MAX7221_INTENSITY, MIN( intensity, 15));}; // bright (0..15)
void shutdown( void) { send_all( MAX7221_SHUTDOWN, 0);}; // power save
void power_on( void) { send_all( MAX7221_SHUTDOWN, 1);}; // power on
void show( void); // show screen
void clear_leds( void); // clear LEDs buffer
void cls( void); // clear screen
void led( byte x, byte y, byte on_off); // LED 1-on/0-off
void box( byte x, byte y, byte xx, byte yy, byte on_off); // draw box
void sprite( byte x, byte y, byte col, byte row, byte * p); // draw sprite
};
#endif // KT_MAX7221M_H
Az első programom éppen ennek az ellenőrzésére, felderítésére szolgált.
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
max7221m d= max7221m( 11); // display Select
void setup()
{
d.bright( 3);
d.leds[ 5]= 0B11111111;
d.led( 0, 0, 1);
d.led( 31, 7, 1);
d.show();
}
void loop()
{
}
A második proggrammal szerettem volna valami dinamikus dolgot kicsalni végre a kijelzőből, ezért egy LED-et villogtattam.
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
max7221m d= max7221m( 11); // display Select
void setup()
{
d.bright( 3);
d.led( 0, 0, 1);
d.led( 31, 7, 1);
}
void loop()
{
d.led( 1, 1, 1);
d.show();
delay( 300);
d.led( 1, 1, 0);
d.show();
delay( 300);
}
Ezek az Invaders spritok elevenedtek meg előszőr a kijelzőmön. Ez a program, már az én library-m alatt fut. Érdemes megfigyelni, hogy sprite-ok tetszőleges helyre pozícionálhatók a képernyőn, nincsenek az adott kijelző chiphez kötve. A sprite fuggvényem legfeljebb 1 byte-os, 8 pontos sprite-ot képes megjeleníteni, szóval lehet kisebb is. A sprite-ok definiálásához elővettem egy korábbi munkámat, csak ki kellett bővítenem. A Cx________ változónak látszó dolgok tulajdonképpen #define utasítással létrehozott szimbólumok, a 0B00000000 bináris változónak felelnek meg, csak jobban látszik mit akarunk kirajzolni, így nem kell grafikus sprite/karakter szerkesztő.
/******************************************************************************
* Author - Kiraly Tibor
* http://www.tkiraaly.hu
* Date - 2019.03.01.
* Chip - Ardiono NANO, MAX7221 matrix display
* Compiler - Arduino IDE
*
* Invaders animacio
*
*******************************************************************************/
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
#include <kt_chardefs.h>
max7221m d= max7221m( 11); // display Select
byte invader0[]=
{
Cx___XX___,
Cx__XXXX__,
Cx_XXXXXX_,
CxXX_XX_XX,
CxXXXXXXXX,
Cx__X__X__,
Cx_X_XX_X_,
CxX_X__X_X
};
byte invader1[]=
{
Cx___XX___,
Cx__XXXX__,
Cx_XXXXXX_,
CxXX_XX_XX,
CxXXXXXXXX,
Cx__X__X__,
Cx_X_XX_X_,
Cx_X____X_
};
byte invader2[]=
{
Cx__X__X__,
Cx__X__X__,
Cx_XXXXXX_,
CxXX_XX_XX,
CxXXXXXXXX,
CxXXXXXXXX,
CxX_X__X_X,
Cx__X__X__
};
byte invader3[]=
{
Cx__X__X__,
CxX_X__X_X,
CxXXXXXXXX,
CxXX_XX_XX,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__X__X__,
Cx_X____X_
};
void setup()
{
d.bright( 3);
}
void loop()
{
d.clear_leds();
d.sprite( 6, 7, 8, 8, invader0);
d.sprite( 18, 7, 8, 8, invader2);
d.show();
delay( 300);
d.clear_leds();
d.sprite( 6, 7, 8, 8, invader1);
d.sprite( 18, 7, 8, 8, invader3);
d.show();
delay( 300);
}
Valamikor láttam ezeket a szemeket, én is szerettem volna megcsinálni. Ez nem nagyon más, mint az előző programom, csak egy kicsit bonyolultabb és nem lináris az animáció.
/******************************************************************************
* Author - Kiraly Tibor
* http://www.tkiraaly.hu
* Date - 2019.03.02.
* Chip - Ardiono NANO, MAX7221 matrix display
* Compiler - Arduino IDE
*
* Eyes animacio
*
*******************************************************************************/
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
#include <kt_chardefs.h>
max7221m d= max7221m( 11); // display Select
byte eye1[]=
{
Cx__XXXX__,
Cx_XXXXXX_,
CxXXXXXXXX,
CxXXX__XXX,
CxXXX__XXX,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__XXXX__
};
byte eye2[]=
{
Cx__XXXX__,
Cx_XXXXXX_,
CxXXXXXXXX,
CxXX__XXXX,
CxXX__XXXX,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__XXXX__
};
byte eye3[]=
{
Cx__XXXX__,
Cx_XXXXXX_,
CxXXXXXXXX,
CxX__XXXXX,
CxX__XXXXX,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__XXXX__
};
byte eye4[]=
{
Cx__XXXX__,
Cx_XXXXXX_,
CxXXXXXXXX,
CxXXXX__XX,
CxXXXX__XX,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__XXXX__
};
byte eye5[]=
{
Cx__XXXX__,
Cx_XXXXXX_,
CxXXXXXXXX,
CxXXXXX__X,
CxXXXXX__X,
CxXXXXXXXX,
Cx_XXXXXX_,
Cx__XXXX__
};
byte eye6[]=
{
Cx________,
Cx________,
Cx________,
Cx_XXXXXX_,
CxXXX__XXX,
CxXXX__XXX,
Cx_XXXXXX_,
Cx________
};
byte eye7[]=
{
Cx________,
Cx________,
Cx________,
Cx________,
Cx__XXXX__,
CxXXXXXXXX,
Cx________,
Cx________
};
void eyes( byte *l, byte *r, int dtime)
{
d.clear_leds();
d.sprite( 6, 7, 8, 8, l);
d.sprite( 18, 7, 8, 8, r);
d.show();
delay( dtime);
}
void setup()
{
d.bright( 3);
}
void loop()
{
eyes( eye1, eye1, 500);
eyes( eye2, eye2, 100); // balra
eyes( eye3, eye3, 300);
eyes( eye2, eye2, 100);
eyes( eye1, eye1, 500);
eyes( eye4, eye4, 100); // jobbra
eyes( eye5, eye5, 300);
eyes( eye4, eye4, 100);
eyes( eye1, eye1, 500);
eyes( eye6, eye6, 30); // pislog
eyes( eye7, eye7, 60);
eyes( eye6, eye6, 30);
}
Mint azt egy ideje tudjuk, minden robantós filmhez szükséges egy hatalmas piros kijelő, amin a visszaszámolást kizárólag az utolsó 3 másodpercben sikerül megállítani. Le van programozva mind a tíz számjegy, csak a gif olyan mérhetetlenül nagy lett, hogy inkább vágtam a felvételből.
/******************************************************************************
* Author - Kiraly Tibor
* http://www.tkiraaly.hu
* Date - 2019.03.02.
* Chip - Ardiono NANO, MAX7221 matrix display
* Compiler - Arduino IDE
*
* Szamok kiirasa ciklikusan 0..9
*
*******************************************************************************/
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
#include <kt_chardefs.h>
max7221m d= max7221m( 11); // display Select
byte szamok[][8]=
{
{
Cx_XXX____,
CxX___X___,
CxX__XX___,
CxX_X_X___,
CxXX__X___,
CxX___X___,
Cx_XXX____,
Cx________
},
{
Cx__X_____,
Cx_XX_____,
Cx__X_____,
Cx__X_____,
Cx__X_____,
Cx__X_____,
Cx_XXX____,
Cx________
},
{
Cx_XXX____,
CxX___X___,
Cx____X___,
Cx___X____,
Cx__X_____,
Cx_X______,
CxXXXXX___,
Cx________
},
{
Cx_XXX____,
CxX___X___,
Cx____X___,
Cx_XXX____,
Cx____X___,
CxX___X___,
Cx_XXX____,
Cx________
},
{
CxX___X___,
CxX___X___,
CxX___X___,
CxXXXXX___,
Cx____X___,
Cx____X___,
Cx____X___,
Cx________
},
{
CxXXXXX___,
CxX_______,
CxX_______,
CxXXXX____,
Cx____X___,
Cx____X___,
CxXXXX____,
Cx________
},
{
Cx_XXX____,
CxX___X___,
CxX_______,
CxXXXX____,
CxX___X___,
CxX___X___,
Cx_XXX____,
Cx________
},
{
CxXXXXX___,
Cx____X___,
Cx____X___,
Cx___X____,
Cx__X_____,
Cx__X_____,
Cx__X_____,
Cx________
},
{
Cx_XXX____,
CxX___X___,
CxX___X___,
Cx_XXX____,
CxX___X___,
CxX___X___,
Cx_XXX____,
Cx________
},
{
Cx_XXX____,
CxX___X___,
CxX___X___,
Cx_XXXX___,
Cx____X___,
CxX___X___,
Cx_XXX____,
Cx________
}
};
void setup()
{
d.bright( 3);
}
void loop()
{
byte i;
for( i= 0; i < 10; i++)
{
d.clear_leds();
d.sprite( 6, 7, 8, 8, szamok[ i]);
d.show();
delay( 700);
}
}
Azután kell egy szöveg kiírására alkalmas program. Az interneten sok matrix betütípus képe megtalálható, de belefoghatunk magunk is a tervezésbe. Készíthetünk saját jeleket is, most a % jel helyére tettem egy szivecskét. Szebb megoldás lett volna, ha a betüket aprogram memóriába rögzítem, és nem RAM-ban, de az az igazság, hogy kevesebb mint 300 byte-ot használtam, belefért. Terjedelmi okokból az alábbi program közepéről kivágtam a betük nagy részét.
/******************************************************************************
* Author - Kiraly Tibor
* http://www.tkiraaly.hu
* Date - 2019.03.03.
* Chip - Ardiono NANO, MAX7221 matrix display
* Compiler - Arduino IDE
*
* Szoveg kiirasa, betu definiciok
*
*******************************************************************************/
#define MAX72XX_CHIPS 4 // number of MAX7221 chips
#define MAX72XX_DIN 12 // UNO, NANO MISO (MEGA - 50)
#define MAX72XX_CLK 10 // UNO, NANO SS (CLK)) (MEGA - 52)
#include <kt_max7221m.h>
#include <kt_chardefs.h>
max7221m d= max7221m( 11); // display Select
byte betuk[][6]=
{
{
Cx__X_____,
Cx_X_X____,
CxX___X___,
CxXXXXX___,
CxX___X___,
'A'
},
{
CxXXXX____,
CxX___X___,
CxXXXX____,
CxX___X___,
CxXXXX____,
'B'
},
.
.
.
{
Cx___X____,
Cx___X____,
Cx___X____,
Cx________,
Cx___X____,
'!'
},
{
Cx________,
Cx________,
Cx________,
Cx________,
Cx__X_____,
'.'
},
{
Cx_X_X____,
CxX_X_X___,
CxX___X___,
Cx_X_X____,
Cx__X_____,
'%'
},
{
CxXXXX____,
Cx____X___,
Cx__XX____,
Cx________,
Cx__X_____,
'?'
}
};
void betu( byte x, byte y, byte c)
{
byte i= 0;
while( betuk[ i][5] != c && betuk[ i][5] != '?') i++;
d.sprite( x, y, 5, 5, betuk[ i]);
}
void szoveg( byte x, byte y, byte *t)
{
while( *t != '\0')
{
betu( x, y, *t);
t++;
x+= 6;
}
}
void setup()
{
d.bright( 3);
szoveg( 4, 6, "EVA%");
d.show();
}
void loop()
{
}
Ennyi az egész, itt a vége, fuss el véle.