Go Down

Topic: Matrix LED 7x7 Projekt mit Multiplexing: Programmierfrage (Read 1 time) previous topic - next topic

dotwinx

Hallo liebe Community,

bin recht frisch bzgl. Arduino und Mikrocontroller. Aber es macht mir tierisch Spaß und ich hoffe ihr könnt mir weiterhelfen. Mein Projekt ist letztlich ein Lern-Projekt für mich selber. Ich habe eine 7x7 LED-Matrix mit einzelnen LEDs aufgebaut und steuere diese durch Multiplexing an. 7 Zeilen/Spalten also 14 Ausgänge, passt für meinen Uno. Der Code des Multiplexing funktioniert analog zu dem Tutorial von Damon Dransfeld.

Nun möchte ich einen Laufbild generieren. Dies mache ich, indem ich jedes einzelne Bild als 7x7 Matrix abspeichere:
Code: [Select]

int j1[7][7] = {{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},};
int j2[7][7] = {{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},};
int j3[7][7] = ...


Problem: Der RAM ist fix voll (egal ob mit int oder byte). Daher hatte ich die idee PROGMEM zu verwenden

Code: [Select]

#include <avr/pgmspace.h>
const int j1[7][7] PROGMEM = {{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},};
const int j2[7][7] PROGMEM = {{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},};
const int j3[7][7] PROGMEM = ...



Nur wenn ich nun die Variablen j1 im Hauptprogramm anwähle
Code: [Select]
void loop() {

  unsigned long timestep = millis();
  if (digitalRead(A0) == HIGH) //Knopf wird gedrückt
  {
    timestep = millis();
    while (millis() < (zeit + timestep))  //So lange wie in "zeit" definiert ist, leuchtet das Bild
          {
             led_7x7_spalten(j1); //Unterfkt. die das Multiplexing macht
          }
  }

kommt nur Murks raus. Habe die Matrizen mir mit Matrix.Print (#include <MatrixMath.h>) im Seriellen Monitor angeschaut, da steht nicht das, was als const PROGMEM definiert wurde. Was mache ich falsch?

Ich hoffe auf einen kurzen Tipp. Vielen Dank

uwefed

Du kannst keine Matrix ohne Transistoren aufbauen.
Die Summe der Ströme einer Reihe LED ist zuviel für einen Arduino-Ausgang.
Grüße Uwe

dotwinx

Transistoren habe ich verbaut, Strom bekommt das ganze mit externer Versorgung. Die Schaltung funktioniert auch. Die Funktion led7x7_Spalten tut was sie soll. Als Eingang das 7x7 array mit 1 oder 0 und die jeweiligen LEDs mit 1 leuchten.

Nur das mit dem Lauflicht klappt nicht, weil ich das <avr/pgmspace.h> wohl falsch verwende. Hast du dazu eine Idee?

agmue

Beim Tutorial - Arduino and the MAX7219 LED Display Driver IC wird Dein Thema gut behandelt, wie ich finde. Das IC mußt Du ja nicht verwenden, obwohl es das Programmieren deutlich vereinfacht.

Einzelne Bits als Integer mit zwei Bytes zu speichern, ist nicht speicherschonend. Sieben Bits passen schön in ein Byte, also:

Code: [Select]
const byte j1[7] PROGMEM = {0b1111111,0,0b1111111,0,0b1111111,0,0b1111111};

EDIT: int in byte
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

dotwinx

Hallo agmue,

vielen Dank für deine Antwort. Dein Link passt wirklich ganz gut zu meinem Problem. Mit einem MAX7219 würde die Ansteuerung deutlich einfacher sein. Aber ich wollte ja gezielt etwas mit der manuellen Programmierung lernen.

Das mit den Bits funktioniert gut, habe ich mal umgesetzt. Aber: Eine Sache die ich euch nicht verraten habe. Derzeit ist es eine 7x7 LED-Matrix. Warum: Wegen der begrenzten Anzahl der Inputs des Arduino Uno. Gelötet habe ich aber eine 10x10 Matrix-LED. Plan ist, dann einen anderen Mikrocontroller zu verwenden, bspw. einen ATMEGA 324 mit 40 Pins.

Vielleicht könnt ihr mir ja nochmal bei meiner Kernfrage helfen: Warum funktioniert die Kombination mit pgmspace.h nicht, wo ist mein Fehler? Im Hauptprogramm kommen keine 0 und 1 an, sondern irgendein Murks.

Code: [Select]

#include <avr/pgmspace.h>
const byte j1[7][7] PROGMEM = {{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},{0,0,0,0,0,0,0},{1,1,1,1,1,1,1},};
...

void loop() {
led_7x7_spalten(j1) }
...

void led_7x7_spalten(byte matrix[7][7])
{
...}

agmue

Eine Konstante im Programmspeicher mußt Du mittels pgm_read_byte_near() lesen. PROGMEM
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

Serenifly

Einzelne Bits als Integer mit zwei Bytes zu speichern, ist nicht speicherschonend. Sieben Bits passen schön in ein Byte, also:

Code: [Select]
const int j1[7] PROGMEM = {0b1111111,0,0b1111111,0,0b1111111,0,0b1111111};
Wobei man dann auch wirklich byte verwenden sollte. Und nicht int


Um zu lernen wie man mit PROGMEM umgeht, gebe die Daten erst mal auf Serial aus. Wie gesagt braucht man da spezielle Funktionen/Makros um auf Daten um Flash zuzugreifen

agmue

Wobei man dann auch wirklich byte verwenden sollte. Und nicht int
Wohl wahr, habe ich korrigiert. Danke.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

dotwinx

Danke für den Tipp... hätte ich auch selbst drauf kommen können :-[

Quote
Um zu lernen wie man mit PROGMEM umgeht, gebe die Daten erst mal auf Serial aus. Wie gesagt braucht man da spezielle Funktionen/Makros um auf Daten um Flash zuzugreifen
... stimmt. Uns so ganz trivial ist das mit meinen eingeschränken Programmierkenntnisse nicht  :o
Mit Serial kann ich überall im Code j1[0[0] bis j1[6][6] ausgeben. Das klappt komischerweise. Wobei ist die Frage was korrekt ist, das
Code: [Select]
Serial.println(j1[0][0]);
oder das
Code: [Select]
Serial.println(pgm_read_byte_near(j1[0][0]));

Mein erster Versuch mit
Code: [Select]
led_7x7_spalten(pgm_read_byte_near(j1))
klappte natürlich nicht, weil pgm_read_byte ja nur eine Variable lesen kann und kein Array oder sogar wie in diesem Fall ein 2D-Array.

Nur geht das überhaupt was ich möchte? Siehe hier. Das 2. Beispiel hier bezieht sich ja nur auf char's mit strcpy. Geht das überhaupt mit 2D-Arrays?

     
     

Serenifly

Du musst die Adresse übergeben. Mit &. Nicht den Inhalt. pgm_read_byte() will eine Adresse und liefert den Inhalt zurück

Code: [Select]

Serial.println(pgm_read_byte_near(&j1[0][0]));


Das _near ist übrigens überflüssig. pgm_read_byte() reicht und ist identisch.

dotwinx

Vielen Dank für eure Antworten. Zwar habe ich es nicht geschafft das gesamte 2D-Array aus dem Flash zu ziehen, aber im Unterprogramm led_7x7_spalten werden eh alle zeilen und spalten einzelnd angefragt. Mit pgm_read_byte(&j1[index1][index2]) hats funktioniert.

Vielen Dank an alle.

Kurze andere Frage: Kann man ein Arduino Bootloader auf beliebige Mikrocontroller flashen, z.B. auf ein Atmega 324PA?
Ich möchte gerne mehr Pins verwenden...

agmue

Grundsätzlich ja, wenn Du einen passenden Bootloader verwendest.
Die Vorstellungskraft ist wichtiger als Wissen, denn Wissen ist begrenzt. (Albert Einstein)

dotwinx

Habs hinbekommen!
Arduino als ISP und Bootloader von MightyCore . Nutze einen ATMEGA324PA-PU. Klappt! Nun kann ich meine 10x10 Matrix aufbauen.
Halte euch auf dem Laufenden...


dotwinx

Hallo liebe Community,

ich habe jetzt doch ein Problem, welches ich nicht gelöst bekomme. Ich hoffe ihr könnt mir helfen. Wenn ich Arduino-Uno als Board unter Werkzeuge angebe, dann kompiliert der Code mit der oben beschriebene Methode mit PROGMEM durch. Am Anfang im Code deklariere ich die 2D-Arrays mit PROGMEM

Code: [Select]
#include <avr/pgmspace.h>
const byte j1[10][10] PROGMEM = {{1,1,1,1,1,1,1,0,0,0},{...


Im Loop rufe ich die Variable auf
Code: [Select]

void loop() {
led_10x10_spalten(j1);
}


und in meiner Funktion steure ich die LEDs an und gebe mit pgm_read_byte die Adresse an:
Code: [Select]
void led_10x10_spalten(byte matrix[10][10])
{...
digitalWrite(z, pgm_read_byte( &matrix[i_z][i_s]) );
...}


Geht. Nur wenn ich jetzt mit dem MightyCore als Board den Ziel-Mikrocontroller 324-PA angebe kommt folgende Fehlermeldung

Quote
Arduino: 1.8.1 (Windows 10), Board: "ATmega324, Standard, 324PA, 2.7v, Disabled (default), 16 MHz external"
[...]
C:\Users\dotwinx\Documents\Arduino\Eigene_Codes\Matrix_3x3\matrix10-10_jede_spalte_einzelnd\matrix10-10_jede_spalte_einzelnd.ino: In function 'void loop()':

matrix10-10_jede_spalte_einzelnd:79: error: invalid conversion from 'const byte (*)[10] {aka const unsigned char (*)[10]}' to 'byte (*)[10] {aka unsigned char (*)[10]}' [-fpermissive]

       led_10x10_spalten(j1);

                           ^

C:\Users\dotwinx\Documents\Arduino\Eigene_Codes\Matrix_3x3\matrix10-10_jede_spalte_einzelnd\matrix10-10_jede_spalte_einzelnd.ino:100:6: note: initializing argument 1 of 'void led_10x10_spalten(byte (*)[10])'

 void led_10x10_spalten(byte matrix[10][10])

      ^

exit status 1
invalid conversion from 'const byte (*)[10] {aka const unsigned char (*)[10]}' to 'byte (*)[10] {aka unsigned char (*)[10]}' [-fpermissive]
Könnt ihr mir sagen was ich anders machen muss, damit das mit dem 324 auch klappt?

Danke und VG

dotwinx

Habe nochmal was herausgefunden was vielleicht hilft. Ich nutze im Boardverwalter das AVR-Board der Version 1.6.17. Das Kompilieren klappt mit den Versionen 1.6.12 bis 1.6.17. Wenn ich 1.6.11 und älter wähle, kommt der gleiche Fehler wie oben beim MightyCore 324.

Go Up