Forum: Compiler & IDEs Problem mit Progmem und LED-Matrix


von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Hallo,
in meinem Projekt verwende ich eine LED-Matrix, auf der ich Zahlen 
ausgeben möchte.
Dafür habe ich die Ziffern von 0 bis 9 jeweils einzeln als
8-bit-Integer-Array im Progmem abgelegt.

In einer Funktion lade ich diese nun aus dem Speicher und gehe Byte für 
Byte ab. Wenn das Byte '1' ist, dann setze ich einen Pixel, wenn '0', 
dann nicht.

Das funktioniert für die Ziffern 0, 3,4,5,6,7,8 und 9 auch ganz toll, 
nur leider werden bei 1 und zwei nur merkwürdige Symbole angezeigt.

Die Symbole habe ich in einer Header-Datei definiert:
1
#include <avr/pgmspace.h>
2
3
const uint8_t one[3][5] PROGMEM= 
4
{{0,0,0,0,0},
5
{0,0,0,0,0},
6
{1,1,1,1,1}};
7
8
const uint8_t two[3][5] PROGMEM=
9
{{1,0,1,1,1},
10
{1,0,1,0,1},
11
{1,1,1,0,1}};
12
13
const int three[3][5] PROGMEM=
14
{{1,0,1,0,1},
15
{1,0,1,0,1},
16
{1,1,1,1,1}};
17
18
//...

Die Routine, mit der ich ein Symbol zeichne sieht so aus:
1
void writeSign(int px, int py, int* sign[3][5], uint8_t color){
2
   for (int x = 0; x < 3; x++) {
3
                for (int y = 0; y < 5; y++) {
4
                    if (pgm_read_byte(&(sign[x][y])) > 0)
5
                     plot(px +x, py +y, color);
6
                    else
7
                       plot(px +x, py +y, BLACK);
8
9
                }
10
               
11
            }
12
}

Wenn ich nun diesen void aufrufe, dann kann ich eine 3 zeichnen, aber 
keine 1 oder 2.

Das hier:
1
writeSign(0,0, &one, GREEN);
2
writeSign(4,0, &two, RED);
3
writeSign(8,0, &three, ORANGE);

Führt zur folgenden Displayausgabe (X für LED an):
1
 XX XX  XXX
2
 XX XX    X
3
 XX XX  XXX
4
  X       X
5
 X      XXX


Könnt ihr mir sagen, was ich da falsch mache?

Mit freundlichen Grüßen,
Valentin Buck

von Karl H. (kbuchegg)


Lesenswert?

Valentin Buck schrieb:

> Wenn ich nun diesen void aufrufe, dann kann ich eine 3 zeichnen,

das ist maximal Zufall

Das hier

void writeSign(int px, int py, int* sign[3][5], uint8_t color){

besagt, dass sign ein 3*5 Array ist, und in diesem Array sind Pointer 
auf int abgelegt. Das hast du aber nicht. Du hast in deinem Array keine 
Pointer, du hast dort uint8_t abgelegt.

Also

void writeSign(int px, int py, uint8_t sign[3][5], uint8_t color){


Der Rest der Funktion kann nach schnellem drüberschauen so bleiben wie 
er ist.

Aufrufseitig

writeSign(0,0, &one, GREEN);

No, kein &. Arrays werden sowieso immer übergeben, in dem die 
Startadresse des Arrays übergeben wird. Da brauchst du (und sollst) du 
nicht selbst den AdressOf Operator anwenden.

von Peter D. (peda)


Lesenswert?

Valentin Buck schrieb:
> Wenn ich nun diesen void aufrufe, dann kann ich eine 3 zeichnen, aber
> keine 1 oder 2.

Weil die unterschiedlich definiert sind (2* 8Bit-, 1* 16Bit-Array).


3*5*16 Bit (int) ist ziemlich verschwenderisch (1400% zuviel).

3*5 = 15Bit, da reicht ein einziges int dicke aus. Die Bitwerte 
ermittelt man mit Schieben.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Peter Dannegger schrieb:
> Valentin Buck schrieb:
>> Wenn ich nun diesen void aufrufe, dann kann ich eine 3 zeichnen, aber
>> keine 1 oder 2.
>
> Weil die unterschiedlich definiert sind (2* 8Bit-, 1* 16Bit-Array).

tatsächlich. Ist mir entgangen.

Da frag ich mich, wie er das überhaupt durch den Compiler gekriegt hat.

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Vielen Dank,
jetzt funktionierts!
Da hab ich wieder was gelernt: Arrays werden nicht mit Pointern 
übergeben!
Danke!

@Peter Dannegger:
Wie würde man das denn machen?
Mit Bitmasken?
Denn da kann man ja wirklich noch viel Speicherplatz sparen (2 Byte 
statt 15)!

Mit freundlichen Grüßen,
Valentin Buck

von Uwe S. (de0508)


Lesenswert?

Hallo,

==> Arrays werden nicht mit Pointern übergeben <==

wie sonst ?

Bitte zeige uns noch mal deinen neuen Code. Danke.

von Karl H. (kbuchegg)


Lesenswert?

Valentin Buck schrieb:
> Vielen Dank,
> jetzt funktionierts!
> Da hab ich wieder was gelernt: Arrays werden nicht mit Pointern
> übergeben!

Doch werden sie.
Aber das passiert sowieso.

Und du hast in der Funktion 2 Möglichkeiten das zu schreiben.
Die eine berücksichtigt, dass ein Array als Pointer auf das erste 
Element übergeben wird
1
void foo( int * data )
2
{
3
  printf( "%d", data[0] );
4
  printf( "%d", data[1] );
5
}
6
7
int main()
8
{
9
  int check[2] = { 2, 3 );
10
11
  foo( check );
12
}

während die andere in der Argumentliste durch die andere Schreibweise 
etwas besser ausdrückt, dass ein Array erwartet wird
1
void foo( int data[] )
2
{
3
  printf( "%d", data[0] );
4
  printf( "%d", data[1] );
5
}
6
7
int main()
8
{
9
  int check[2] = { 2, 3 );
10
11
  foo( check );
12
}

Passieren tut aber in beiden Fällen genau das gleiche: es wird ein 
Pointer übergeben. Die [] Schreibweise ist nur syntaktischer Zucker.


> Danke!
>
> @Peter Dannegger:
> Wie würde man das denn machen?
> Mit Bitmasken?

Ein ganzes Byte kann 8 Pixel darstellen. Du musst die Bits nur 
rausholen. Ganz stink normale Bitoperationen, wie sie in jedem 
AVR-Programm massenhaft vorkommen.

Bitmanipulation

von Peter D. (peda)


Lesenswert?

1
void writeSign(int px, int py, uint16_t pattern, uint8_t color){
2
   for (int x = 0; x < 3; x++) {
3
                for (int y = 0; y < 5; y++) {
4
                    if (pattern & 1)                // LSB first
5
                     plot(px +x, py +y, color);
6
                    else
7
                       plot(px +x, py +y, BLACK);
8
                    pattern >>= 1;                  // next bit
9
                }
10
               
11
            }
12
}

pattern ist der 16Bit Wert (Bit 0 .. 14), einen Pointer brauchst Du 
nicht mehr.


Peter

von Valentin B. (nitnelav) Benutzerseite


Lesenswert?

Danke für die Erklärung und den Lösungsansatz!
Das spart für alle Zeichen so etwa 500 Bytes Programmspeicher!

Ich hab dann mal einen Generator für Zeichen im 3x5-Font geschrieben.
Wer so was braucht, kann ihn hier runterladen:
http://apexys-toan.blogspot.com/2011/08/simple-3x5-binary-font-generator.html

Nochmals vielen Dank!

Mit freundlichen Grüßen,
Valentin Buck

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.