Forum: Mikrocontroller und Digitale Elektronik Pointer auf Array in einer for schleife


von MO (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

Hab ein Problem mit einem Pointer auf ein Array im Flash und bitte um 
Hilfe/Aufklährung warum es nicht klappt.

Ich versuche zu verstehen wie Pointer angewendet werden indem ich ein 
Menü ausgebe welches sich in einem Array befindet das durch einen 
Pointer aufgerufen wird.


Warum funktioniert dieser teil:
1
write_str_p(MENU[0], 5, 10, WHT, RED);
2
write_str_p(MENU[1], 5, 18, WHT, RED);
3
write_str_p(MENU[2], 5, 26, WHT, RED);

und dieser teil nicht:
1
for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
2
{
3
write_str_p(MENU[i], 5, j+=10, WHT, RED);
4
}

hier erscheinen auf dem Display irgendwelche zeichen auf der gesamten 
zeile und das drei mal hintereinander

Im Anhang sind die source Dateien zu finden.

MfG

von Thomas K. (tomthegeek)


Lesenswert?

Hi

kannst du bitte mal den kompletten Code posten, speziell den Teil an dem 
das Menü initialisiert wird.
Und bitte mal schaun, was bei sizeof(MENU)/sizeof(*MENU) herauskommt.

Thomas

von MO (Gast)


Lesenswert?

Hallo Thomas

in der *.h Datei:
1
//STRINGS IN FLASH
2
const char txt1[] PROGMEM = "Farben";
3
const char txt2[] PROGMEM = "Contrast";
4
const char txt3[] PROGMEM = "Helligkeit";
5
6
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};

Das ist die write_str_p Funktion
1
void write_str_p(const char *p, unsigned char x, unsigned char y, unsigned short fcol, unsigned short bcol)
2
{
3
  unsigned char c;
4
  while (((c = pgm_read_byte(p++))!=0))
5
  {
6
    write_char(c,x,y,fcol,bcol);
7
    x += fontw;
8
  //_delay_ms(1000);
9
  }
10
}

Und Main
1
#include <avr\io.h>
2
#include <mylib\FONT\C\6x8_horizontal_MSB_1.h>
3
#include <util\delay.h>
4
#include <mylib\Driver\st7637.c>
5
6
7
8
9
int main(void)
10
{
11
  mcu_init();
12
  disp_init();
13
14
  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
15
  {
16
  write_str_p(MENU[i], 5, j+=10, WHT, RED);
17
  }
18
19
  while(1);
20
21
  return 0;
22
}

MfG

von Klaus W. (mfgkw)


Lesenswert?

In der ersten Version hast du als y die Werte 10, 18 und 26.
In der for-Variante 10, 20 30.
Vielleicht liegt es ja daran.

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:
> Hallo Thomas
>
> in der *.h Datei:
>
1
> //STRINGS IN FLASH
2
> const char txt1[] PROGMEM = "Farben";
3
> const char txt2[] PROGMEM = "Contrast";
4
> const char txt3[] PROGMEM = "Helligkeit";
5
> 
6
> const  char *MENU[] PROGMEM = { txt1,txt2,txt3};
7
>

Das kann aber mit deiner ursprünglichen Version
1
write_str_p(MENU[0], 5, 10, WHT, RED);
2
write_str_p(MENU[1], 5, 18, WHT, RED);
3
write_str_p(MENU[2], 5, 26, WHT, RED);
nicht funktioniert haben :-)

Du hast 2 Dinge die im Flash liegen.

sowohl MENU als auch die Pointer die in MENU gespeichert sind, liegen im 
Flash.
Um also den Pointer auf den Text zu bekommen, musst du schon einmal aus 
dem Flash lesen. Und das tust du nicht.
1
  char * txtPointer;
2
3
  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
4
  {
5
    txtPointer = (char*)pgm_read_word( &MENU[i] );
6
    write_str_p( txtPointer, 5, j+=10, WHT, RED );
7
  }

von Karl H. (kbuchegg)


Lesenswert?

PS:
In C hat man die Konvention, dass Namen die ausschliesslich in 
Grossbuchstaben geschrieben sind, immer ein Makro kennzeichnen. Es gibt 
keinen Grund von dieser Konvention abzuweichen, zumal das eine der 
wenigen Konventionen ist, die tatsächlich von so gut wie allen 
C-Programmierern eingehalten wird.

von MO (Gast)


Lesenswert?

Hallo Karl heinz Buchegger

In der *.c Datei genauer hier
1
void write_str_p(const char *p, unsigned char x, unsigned char y, unsigned short fcol, unsigned short bcol)
2
{
3
  unsigned char c;
4
>>  while (((c = pgm_read_byte(p++))!=0))
5
  {
6
    write_char(c,x,y,fcol,bcol);
7
    x += fontw;
8
  //_delay_ms(1000);
9
  }
10
}

Wird ja auf den Flash zugegriffen.

Das hier z.B. geht und es wird 3 mal Farben untereinander angezeigt.
1
for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
2
  {
3
  write_str_p(MENU[0], 5, j+=10, WHT, RED);
4
  }

Das Problem liegt irgendwie in der incrementierung von i!?

MfG

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:

> Wird ja auf den Flash zugegriffen.

Nochmal:
Du hast eine 2 stufige Datenstruktur die komplett im Flash liegt.


>
> Das hier z.B. geht und es wird 3 mal Farben untereinander angezeigt.
>
1
> for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
2
>   {
3
>   write_str_p(MENU[0], 5, j+=10, WHT, RED);
4
>   }
5
> 
6
>

das kann nicht funktionieren. Höchstens zufällig. Oder aber du hast das 
zu einem Zeitpunkt getestet, als deine Datenstruktur noch so aussah
1
const  char *MENU[] = { txt1,txt2,txt3};
Jetzt liegt MENU nicht im Flash und du kannst den i-ten Pointer mittels 
MENU[i] bekommen.


Deine Struktur sieht aber so aus
1
const char txt1[] PROGMEM = "Farben";
2
const char txt2[] PROGMEM = "Contrast";
3
const char txt3[] PROGMEM = "Helligkeit";
4
 
5
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};

sowohl das Array "MENU" als auch die Texte liegen im Flash:
1
   MENU
2
   +---------+
3
   |   o--------------------> "Farben"
4
   +---------+
5
   |   o--------------------------> "Contrast"
6
   +---------+
7
   |   o----------> "Helligkeit"
8
   +---------+

Um also an die Pointer zu kommen, die du dann an write_str_p übergeben 
kannst, musst du sie aus MENU auslesen. Da aber MENU selbst auch im 
Flash liegt, musst du die Flash Funktionen benutzen um an diesen Pointer 
zu gelangen.

>
> Das Problem liegt irgendwie in der incrementierung von i!?

Ganz sicher nicht.

von Thomas K. (tomthegeek)


Lesenswert?

dann probier doch mal folgendes:
1
int i;
2
for(i=0;i<sizeof(MENU)/sizeof(*MENU);i++)
3
  {
4
  write_str_p(MENU[i], 5, 10+8*i, WHT, RED);
5
  }

By the way: gibt j+=10 überhaupt was zurück?

Thomas

von Karl H. (kbuchegg)


Lesenswert?

Thomas K. schrieb:
> dann probier doch mal folgendes:
>
>
1
> int i;
2
> for(i=0;i<sizeof(MENU)/sizeof(*MENU);i++)
3
>   {
4
>   write_str_p(MENU[i], 5, 10+8*i, WHT, RED);
5
>   }
6
>
>

Was soll das bringen?
Sein Textpointer ist schon falsch

> By the way: gibt j+=10 überhaupt was zurück?

Natürlich. Den neuen Wert von j.

von MO (Gast)


Lesenswert?

Ich verstehe jetzt nur Bahnhof.

Mit diesem Code steht auf den Display 3mal untereinander "Contrast".
1
int main(void)
2
{
3
  mcu_init();
4
  disp_init();
5
6
  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
7
  {
8
  write_str_p(MENU[1], 5, j+=10, WHT, RED);
9
  }
10
11
  while(1);
12
13
  return 0;
14
}


Ich gebe doch der Function "write_str_p" die Adresse des Eintrages in 
der 2ten zeile(quasi txt2 also "Contrast") dessen Adresse im Pointer 
"MENU[1]" steht.
und hiermit:

>>  while (((c = pgm_read_byte(p++))!=0))

greife ich doch auf dem Flash zu!?

was auch klappt.

!!!ABER!!!

Benutze ich statt der 1 das i also "MENU[i]" um in der Schleife alle 3 
einträge auszugeben, liest/zeigt der µC andere zeichen an.

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:
> Ich verstehe jetzt nur Bahnhof.

Machs einfach so, wie ich es dir gezeigt habe

> Ich gebe doch der Function "write_str_p" die Adresse des Eintrages in
> der 2ten zeile(quasi txt2 also "Contrast") dessen Adresse im Pointer
> "MENU[1]" steht.

Ja.
Aber wo hast du den denn her?
Der richtige steht doch selber wieder im Flash!

Dein MENU Array steht im Flash!
Wenn du von dort etwas auslesen willst (zb einen Pointer), dann musst du 
dafür die Flash Funktionen benutzen. Was du dann mit dem Pointer weiter 
machst, steht hier nicht zur Debatte. Um von MENU zu lesen musst du über 
die Flash Funktionen gehen. Das ist so, weil du hier
1
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};

das MENU Array als ganzes ins Flash verfrachtet hast. Da gehts noch 
nicht mal darum, was denn im MENU Array enthalten ist. Und wenn das 
einfach nur ein paar Zahlen wären: Um von MENU etwas zu lesen, musst du 
die Flash Funktionen benutzen.

> und hiermit:
>
>>>  while (((c = pgm_read_byte(p++))!=0))
>
> greife ich doch auf dem Flash zu!?

Das ist uninteressant. die Funktion ist schon ok.
Du hast ganz einfach nicht den richtigen Pointer

von (prx) A. K. (prx)


Lesenswert?

Karl heinz Buchegger schrieb:

> Das kann aber mit deiner ursprünglichen Version
>
1
> write_str_p(MENU[0], 5, 10, WHT, RED);
2
> write_str_p(MENU[1], 5, 18, WHT, RED);
3
> write_str_p(MENU[2], 5, 26, WHT, RED);
4
>
> nicht funktioniert haben :-)

Doch, weil der Compiler den Zugriff auf's Array wegoptimiert hat. Das 
Array ist "const", da darf er das.

von (prx) A. K. (prx)


Lesenswert?

MO schrieb:

> Ich verstehe jetzt nur Bahnhof.

MENU liegt im Flash, MENU[i] liest aus RAM => Schrott.

Also ungefähr so:
1
char *p = pgm_read_word(&MENU[i]);
2
write_str_p(p, 5, j+=10, WHT, RED);

von MO (Gast)


Lesenswert?

Hab das jetzt so in der .h Datei und es klapp nun auch in der Schleife.
1
//STRINGS IN FLASH
2
const char txt1[] PROGMEM = "Farben";
3
const char txt2[] PROGMEM = "Contrast";
4
const char txt3[] PROGMEM = "Helligkeit";
5
6
const char *ptrMENU[] = { txt1,txt2,txt3};

und das ist mein MAIN.
1
int main(void)
2
{
3
  mcu_init();
4
  disp_init();
5
6
  for(int i=0,j=0;i<sizeof(ptrMENU)/sizeof(*ptrMENU);i++)
7
  {
8
  write_str_p(ptrMENU[i], 5, j+=10, WHT, RED);
9
  }
10
11
  while(1);
12
13
  return 0;
14
}

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:
> Hab das jetzt so in der .h Datei und es klapp nun auch in der Schleife.
>
>
1
> //STRINGS IN FLASH
2
> const char txt1[] PROGMEM = "Farben";
3
> const char txt2[] PROGMEM = "Contrast";
4
> const char txt3[] PROGMEM = "Helligkeit";
5
> 
6
> const char *ptrMENU[] = { txt1,txt2,txt3};
7
>
>

Jetzt hast du das ptrMENU Array aus dem Flash rausgenommen.
Klar klappt nun ein Zugriff mittels ptrMENU[i]

(Aber eigentlich hast du geschummelt und bist deinem Verständnisproblem 
ausgewichen :-)

von pedant (Gast)


Lesenswert?

1
const char txt1[] PROGMEM = "Farben\0";
2
const char txt2[] PROGMEM = "Contrast\0";
3
const char txt3[] PROGMEM = "Helligkeit\0";

von Karl H. (kbuchegg)


Lesenswert?

pedant schrieb:
>
1
const char txt1[] PROGMEM = "Farben\0";
2
> const char txt2[] PROGMEM = "Contrast\0";
3
> const char txt3[] PROGMEM = "Helligkeit\0";

Und wozu soll das wieder gut sein? Die abschliessende '\0' macht dir 
doch der Compiler sowieso bei einem String immer hinten drann. Ganz von 
alleine.

von MO (Gast)


Lesenswert?

BÖSER JUNGE ;)

Was ich verstanden hab ist, dass ich mit
>>char *ptrMENU[] PROGMEN = { txt1,txt2,txt3};
auf dem Flash zugreife was mir auch klar war und ich nur mit
>>pgm_read_byte(ptr) bzw. pgm_read_word(ptr)
Daten aus dem Flash holen kann auch klar.

Was mich aber stutig gemacht hat ist, warum es hier mit geht (das ging 
wirklich)
> write_str_p(MENU[0], 5, 10, WHT, RED);
> write_str_p(MENU[1], 5, 18, WHT, RED);
> write_str_p(MENU[2], 5, 26, WHT, RED);
 aber nicht hiermit
> for(int i=0,j=0;i<sizeof(ptrMENU)/sizeof(*ptrMENU);i++)
>  {
>  write_str_p(ptrMENU[i], 5, j+=10, WHT, RED);
>  }

Danke euch für die Hilfe.

MfG

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:

> Was mich aber stutig gemacht hat ist, warum es hier mit geht (das ging
> wirklich)

Daran hab ich auch nicht mehr gedacht. A.K. hatte die Lösung. Das 
funktionierte wegen "works by Optimization". Hättest du den Optimizer 
abgeschaltet, hätte es ebenfalls nicht mehr funktioniert.

Der Compiler kennt ja den Wert von MENU[0]. Er hat ihn ja vorher 
gesehen. Also hat er ganz einfach für dich mitgedacht und anstelle eines 
Zugriffs auf MENU[0] gleich den richtigen Wert in den Code eingesetzt. 
Drum hat das funktioniert.

Also Zufall. Wenn der Compiler den Arrayinhalt vorher nicht gesehen 
hätte, hätte auch der Optimizer das nicht irrtümlich hinbiegen können.

von MO (Gast)


Lesenswert?

Verzeit mir das doppelposting

Geht das was ich vorhab auch eleganter und/oder schöner?

MfG

von Karl H. (kbuchegg)


Lesenswert?

MO schrieb:
> Verzeit mir das doppelposting
>
> Geht das was ich vorhab auch eleganter und/oder schöner?

So wie ich es dir weiter oben gezeigt habe. Dann liegt alles im Flash.

Man könnte das höchstens noch zusammenfassen:
1
//STRINGS IN FLASH
2
const char txt1[] PROGMEM = "Farben";
3
const char txt2[] PROGMEM = "Contrast";
4
const char txt3[] PROGMEM = "Helligkeit";
5
 
6
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};
7
8
9
....
10
 
11
  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
12
  {
13
    write_str_p( (char*)pgm_read_word( &MENU[i] ), 5, j+=10, WHT, RED );
14
  }

ob as allerdings eleganter bzw. schöner ist, darüber kann man trefflich 
diskutieren.

Was aber wahrscheinlich nicht so bleiben wird, ist die Verwendung der 
sizeof zur Bestimmung der Arraygröße. Im Endeffekt wirst du ja eine 
einzige Routine haben, die verschiedene Menüs ausgeben kann, jedes mit 
seiner eigenen Größe.
Ausserdem hast du ja noch keine Funktionalität an deine 'Menuüs' 
gekoppelt, so dass du demnächst wahrscheinlich sowieso dieses 
PointerArray wieder auflösen und durch Strukturen ersetzen wirst.

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.