maxim 7219

Hallo Allerseits,

Ich habe mir ein 8X8-Modul mit MAXIM7219 gekauft und an einen uno r3 angeschlossen.

den folgenden Sketch habe ich aus dem Internet und selbst ein wenig angepasst:

/**********************
  * C O N S T A N T S  *
  **********************/
 // Register
    const byte NO_OP        = 0x00;
    const byte DECODE_MODE  = 0x09;                   
    const byte INTENSITY    = 0x0a;
    const byte SCAN_LIMIT   = 0x0b;
    const byte SHUTDOWN     = 0x0c;
    const byte DISPLAY_TEST = 0x0f;

/***************************
 * D E C L A R A T I O N S *
 ***************************/
 
 // PIN  2 : CLK (Clock)
    int clkPin;
 
 // PIN  3 : LOAD
    int loadPin;

 // PIN  4 : DIN (Data)
    int dataPin;
    
 // PIN 13 : monitor
    int outPin;

 // number of digits / lines (+ 1)
    byte digits;

 // line
    byte line;

 // column
    byte column;

 /***********************
  * P R O C E D U R E S *
  ***********************/

 // send data
    void send16Bit(word data)
    {
     // Mask for single bit
     // start with MSB
     // 1000 0000 0000 0000
        word mask = 0x8000;
        
     // for each bit
        do
        {
            digitalWrite(clkPin, LOW);

            if((data & mask) > 0)
                digitalWrite(dataPin, HIGH);
            else
                digitalWrite(dataPin, LOW);
            
            digitalWrite(clkPin, HIGH);

         // shift one bit
            mask = mask >> 1;            
        }while(mask > 0);
    }
    
 // Command register and data
    void sendCommand(byte address, byte data)
    {
     // load to 1 for sending
        digitalWrite(loadPin, 1 );

     // send
        send16Bit((address<<8) | data);
        
     // load to 0 for latch
        digitalWrite(loadPin, 0);
    }
    
 // test display
    void testDisplay(boolean test)
    {
        if(test)
            sendCommand(DISPLAY_TEST, 1);
        else
            sendCommand(DISPLAY_TEST, 0);
    }
    
 // all off
    void clearDisplay()
    {
     // all lines
        sendCommand(SCAN_LIMIT, 7);
        
        for(int line=1; line<=8; ++line)
        {
            sendCommand(line, 0);
        }
        
     // reset scan limit
        sendCommand(SCAN_LIMIT, digits);
    }

 // brightness
 // 0 .. 15
    void setBrightness(byte value)
    {
        sendCommand(INTENSITY, value);
    }
    
 // switch LED in line and col
    void switchLED(byte line, byte column, boolean on)
    {
        if(on)
            sendCommand(line, 1<<column);
        else
            sendCommand(line, 0);
                  
    }

 /***********************
  * I N I T I A L I Z E *
  ***********************/
    void setup()
    {
      
     // Clock
        clkPin  = 2;
        pinMode(clkPin,  OUTPUT);     

     // Load
        loadPin = 3;
        pinMode(loadPin, OUTPUT);     

     // Data
        dataPin = 4;
        pinMode(dataPin, OUTPUT);
        
        outPin = 13;
        pinMode(outPin, OUTPUT);
   
     // number of digits / lines (+ 1)
        digits = 7;

        sendCommand(SHUTDOWN, 1);
        
     // clear all LED's
        clearDisplay();
        
     // set number of digits / lines
        sendCommand(SCAN_LIMIT, digits);
         
     // matrix
        sendCommand(DECODE_MODE, 0);

        line   = 1;
        column = 1;
    }

 // the loop routine runs over and over again forever:
    void loop()
    {
        delay(100);

        column = ++column%8;

        digitalWrite(outPin, column%2);        

        if(column == 0)
        {
        switchLED(line, column, false);
            ++line;
            if(line>8)
            {
                line = 1;
            }                            
        }
        switchLED(line, column, true);
    }

da soll dann, so als ersten einstieg eine LED durchlaufen.

Meist funktioniert es gut, aber manchmal passiert nach dem einschalten gar nichts, oder alle leuchten gleichzeitig.

Hat jemand eine Idee?

Was habe ich falsch gemacht?

hast DU irgendwo einen Wackelkontakt?
Grüße Uwe

Getafix:
Hat jemand eine Idee?

Was habe ich falsch gemacht?

Bist Du Dir sicher, dass line von 1 bis 8 laufen soll:

for(int line=1; line<=8; ++line)
{
  sendCommand(line, 0);
}

Typischerweise würdest Du line von 0 bis 7 laufen lassen, mit einer Schleifenlogik:

for(int line=0; line<8; line++)
{
  sendCommand(line, 0);
}

Ob das bei Dir ein Fehler ist, weiß ich nicht.
Aber das mit der Schleife sieht aus, als wenn es nicht von einem C/C++-Programmierer programmiert wurde.

column läuft doch auch von 0 bis 7, warum dann nicht auch line?

Das gleiche tritt weiter unten auch auf:

 ++line;
 if(line>8)
{
  line = 1;
}

Im übrigen empfehle ich Dir dringend, nachdem Du die Leitungen auf OUTPUT gesetzt hast, ein kleines delay von 50 Millisekunden in der setup-Funktion zu machen, bevor Du den ersten Befehl an den MAX7219 sendest.

     // Clock
        clkPin  = 2;
        pinMode(clkPin,  OUTPUT);     
     // Load
        loadPin = 3;
        pinMode(loadPin, OUTPUT);     
     // Data
        dataPin = 4;
        pinMode(dataPin, OUTPUT);
        outPin = 13;
        pinMode(outPin, OUTPUT);
        delay(50);  // ==> WICHTIG!

Ich danke euch für eure Antworten.

  • Wackelkontakte sind bei einem solchen fliegenden Aufbau natürlich immer drin,
    ich werde das einmal untersuchen

  • line: seltsamerweise läuft line tatsächlich von 1 bis 8 und nicht, wie eigentlich zu vermuten, von 0 bis 7.
    trotzdem danke ich euch für die freundlichen Hinweise.

mache mich dann mal auf die Suche...

Getafix:
mache mich dann mal auf die Suche...

Ich habe mal etwas mit dem Code experimentiert.

Bei meiner LED-Matrix scheint der Controller sehr empfindlich darauf zu reagieren, wenn bei zwei aufeinanderfolgenden Befehlen in derselben Zeile alle LEDs ausgeschaltet werden und unmittelbar danach wird wieder eine LED eingeschaltet.

Das funktioniert bei mir nur, wenn nach dem Ausschalten ein kleines Delay von z.B. 1 Millisekunde eingefügt wird.

void loop()
{
  sendCommand(line+1,0); // Zeile mit der gesetzten LED ausschalten
  delay(1); // eine Millisekunde delay

  column++;      // LED logisch weitersetzen
  if (column>=8)
  {
    line=(line+1)%8;
    column=0;
  }
  sendCommand(line+1, 1<<column); // Zeile mit der gesetzten LED einschalten
  delay(75);
}

Noch besser (hellere LED) funktioniert es allerdings, immer reihum alle 8 Zeilen nacheinander auszugeben, so dass niemals dieselbe Zeile zweimal direkt nacheinander angesteuert wird:

void loop()
{
  column++;      // LED logisch weitersetzen
  if (column>=8)
  {
    line=(line+1)%8;
    column=0;
  }
  for (int row=0;row<8;row++) // Alle Zeilen nacheinander ausgeben
  {
    if(row==line)
      sendCommand(row+1, 1<<column);
    else  
      sendCommand(row+1, 0);
  }
  delay(75);
}

danke schön,

das hört sich sehr interessant an; werde ich heute abend mal ausprobieren

Hallo,

so scheint' nun zu gehen:

/**********************
  * C O N S T A N T S  *
  **********************/
 // Register
    const byte NO_OP        = 0x00;
    const byte DECODE_MODE  = 0x09;                   
    const byte INTENSITY    = 0x0a;
    const byte SCAN_LIMIT   = 0x0b;
    const byte SHUTDOWN     = 0x0c;
    const byte DISPLAY_TEST = 0x0f;

/***************************
 * D E C L A R A T I O N S *
 ***************************/
 
 // PIN  2 : CLK (Clock)
    int clkPin;
 
 // PIN  3 : LOAD
    int loadPin;

 // PIN  4 : DIN (Data)
    int dataPin;
    
 // PIN 13 : monitor
    int outPin;

 // number of digits / lines (+ 1)
    byte digits;

 // line
    byte line;

 // column
    byte column;

 /***********************
  * P R O C E D U R E S *
  ***********************/

 // send data
    void send16Bit(word data)
    {
     // Mask for single bit
     // start with MSB
     // 1000 0000 0000 0000
        word mask = 0x8000;
        
     // for each bit
        do
        {
            digitalWrite(clkPin, LOW);

            if((data & mask) > 0)
                digitalWrite(dataPin, HIGH);
            else
                digitalWrite(dataPin, LOW);
            
            digitalWrite(clkPin, HIGH);

         // shift one bit
            mask = mask >> 1;            
        }while(mask > 0);
    }
    
 // Command register and data
    void sendCommand(byte address, byte data)
    {
     // load to 1 for sending
        digitalWrite(loadPin, 1 );

     // send
        send16Bit((address<<8) | data);
        
     // load to 0 for latch
        digitalWrite(loadPin, 0);
    }
    
 // test display
    void testDisplay(boolean test)
    {
        if(test)
            sendCommand(DISPLAY_TEST, 1);
        else
            sendCommand(DISPLAY_TEST, 0);
    }
    
 // all off
    void clearDisplay()
    {
     // all lines
        sendCommand(SCAN_LIMIT, 7);
        
        for(int line=1; line<=8; ++line)
        {
            sendCommand(line, 0);
        }
        
     // reset scan limit
        sendCommand(SCAN_LIMIT, digits);
    }

 // brightness
 // 0 .. 15
    void setBrightness(byte value)
    {
        sendCommand(INTENSITY, value);
    }
    
 // switch LED in line and col
    void switchLED(byte line, byte column, boolean on)
    {
        if(on)
            sendCommand(line, 1<<column);
        else
            sendCommand(line, 0);
                  
    }

 /***********************
  * I N I T I A L I Z E *
  ***********************/
    void setup()
    {
      
     // Clock
        clkPin  = 2;
        pinMode(clkPin,  OUTPUT);     

     // Load
        loadPin = 3;
        pinMode(loadPin, OUTPUT);     

     // Data
        dataPin = 4;
        pinMode(dataPin, OUTPUT);
        
        outPin = 13;
        pinMode(outPin, OUTPUT);
   
     // number of digits / lines (+ 1)
        digits = 7;

        sendCommand(SHUTDOWN, 1);
        delay(1);

        
     // clear all LED's
        clearDisplay();
        
     // set number of digits / lines
        sendCommand(SCAN_LIMIT, digits);

     // matrix
        sendCommand(DECODE_MODE, 0);

        line   = 1;
        column = 0;
    }

 // the loop routine runs over and over again forever:
    void loop()
    {
        switchLED(line, column, true);

        delay(50);

        column = ++column%8;

        digitalWrite(outPin, column%2);        

        if(column == 0)
        {
        switchLED(line, column, false);
            ++line;
            if(line>8)
            {
                line = 1;
            }                            
        }
    }

Getafix:
so scheint' nun zu gehen:

Ja klar, das funktioniert natürlich auch:

  • Die Zeile mit der eingeschalteten LED ausgeben.
  • ein kleines delay abwarten
  • Und diese LED-Zeile nur dann löschen, wenn die LED im nächsten Schritt in die nächste Zeile springt

Auch damit verhinderst Du, dass dieselbe Zeile ohne Pause dazwischen nochmals angesteuert wird.

Für umfangreichere Darstellungen mit mehreren sich ändernden LEDs, z.B. zum Anzeigen verschiedener Muster oder Buchstaben und Ziffern oder gar scrollendem Text brauchst Du sowieso eine andere Ausgabelogik, bei der immer 8 Zeilen nacheinander angesteuert werden.

das stimmt, da mache ich mich als Nächstes dran

Danke schön, ich melde mich...
:slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: