MAX7221 LED mátrix megszelídítése

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.