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
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.
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
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.
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
Hallo,
==> Arrays werden nicht mit Pointern übergeben <==
wie sonst ?
Bitte zeige uns noch mal deinen neuen Code. Danke.
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
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
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.
|