www.mikrocontroller.net

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


Autor: MO (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
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);

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

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

Autor: Thomas K. (tomthegeek)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Thomas

in der *.h Datei:
//STRINGS IN FLASH
const char txt1[] PROGMEM = "Farben";
const char txt2[] PROGMEM = "Contrast";
const char txt3[] PROGMEM = "Helligkeit";

const  char *MENU[] PROGMEM = { txt1,txt2,txt3};

Das ist die write_str_p Funktion
void write_str_p(const char *p, unsigned char x, unsigned char y, unsigned short fcol, unsigned short bcol)
{
  unsigned char c;
  while (((c = pgm_read_byte(p++))!=0))
  {
    write_char(c,x,y,fcol,bcol);
    x += fontw;
  //_delay_ms(1000);
  }
}

Und Main
#include <avr\io.h>
#include <mylib\FONT\C\6x8_horizontal_MSB_1.h>
#include <util\delay.h>
#include <mylib\Driver\st7637.c>




int main(void)
{
  mcu_init();
  disp_init();

  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
  {
  write_str_p(MENU[i], 5, j+=10, WHT, RED);
  }

  while(1);

  return 0;
}

MfG

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MO schrieb:
> Hallo Thomas
>
> in der *.h Datei:
>
> //STRINGS IN FLASH
> const char txt1[] PROGMEM = "Farben";
> const char txt2[] PROGMEM = "Contrast";
> const char txt3[] PROGMEM = "Helligkeit";
> 
> const  char *MENU[] PROGMEM = { txt1,txt2,txt3};
> 

Das kann aber mit deiner ursprünglichen Version
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);
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.
  char * txtPointer;

  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
  {
    txtPointer = (char*)pgm_read_word( &MENU[i] );
    write_str_p( txtPointer, 5, j+=10, WHT, RED );
  }

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl heinz Buchegger

In der *.c Datei genauer hier
void write_str_p(const char *p, unsigned char x, unsigned char y, unsigned short fcol, unsigned short bcol)
{
  unsigned char c;
>>  while (((c = pgm_read_byte(p++))!=0))
  {
    write_char(c,x,y,fcol,bcol);
    x += fontw;
  //_delay_ms(1000);
  }
}

Wird ja auf den Flash zugegriffen.

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


Das Problem liegt irgendwie in der incrementierung von i!?

MfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
>
> for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
>   {
>   write_str_p(MENU[0], 5, j+=10, WHT, RED);
>   }
> 
> 

das kann nicht funktionieren. Höchstens zufällig. Oder aber du hast das 
zu einem Zeitpunkt getestet, als deine Datenstruktur noch so aussah
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
const char txt1[] PROGMEM = "Farben";
const char txt2[] PROGMEM = "Contrast";
const char txt3[] PROGMEM = "Helligkeit";
 
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};

sowohl das Array "MENU" als auch die Texte liegen im Flash:
   MENU
   +---------+
   |   o--------------------> "Farben"
   +---------+
   |   o--------------------------> "Contrast"
   +---------+
   |   o----------> "Helligkeit"
   +---------+

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.

Autor: Thomas K. (tomthegeek)
Datum:

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

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

Thomas

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

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.

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich verstehe jetzt nur Bahnhof.

Mit diesem Code steht auf den Display 3mal untereinander "Contrast".
int main(void)
{
  mcu_init();
  disp_init();

  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
  {
  write_str_p(MENU[1], 5, j+=10, WHT, RED);
  }

  while(1);

  return 0;
}



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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:

> Das kann aber mit deiner ursprünglichen Version
>
> 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);
> 
> nicht funktioniert haben :-)

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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MO schrieb:

> Ich verstehe jetzt nur Bahnhof.

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

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

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab das jetzt so in der .h Datei und es klapp nun auch in der Schleife.
//STRINGS IN FLASH
const char txt1[] PROGMEM = "Farben";
const char txt2[] PROGMEM = "Contrast";
const char txt3[] PROGMEM = "Helligkeit";

const char *ptrMENU[] = { txt1,txt2,txt3};

und das ist mein MAIN.
int main(void)
{
  mcu_init();
  disp_init();

  for(int i=0,j=0;i<sizeof(ptrMENU)/sizeof(*ptrMENU);i++)
  {
  write_str_p(ptrMENU[i], 5, j+=10, WHT, RED);
  }

  while(1);

  return 0;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
MO schrieb:
> Hab das jetzt so in der .h Datei und es klapp nun auch in der Schleife.
>
>
> //STRINGS IN FLASH
> const char txt1[] PROGMEM = "Farben";
> const char txt2[] PROGMEM = "Contrast";
> const char txt3[] PROGMEM = "Helligkeit";
> 
> const char *ptrMENU[] = { txt1,txt2,txt3};
> 
>

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 :-)

Autor: pedant (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
const char txt1[] PROGMEM = "Farben\0";
const char txt2[] PROGMEM = "Contrast\0";
const char txt3[] PROGMEM = "Helligkeit\0";

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pedant schrieb:
>
const char txt1[] PROGMEM = "Farben\0";
> const char txt2[] PROGMEM = "Contrast\0";
> 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.

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: MO (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verzeit mir das doppelposting

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

MfG

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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:
//STRINGS IN FLASH
const char txt1[] PROGMEM = "Farben";
const char txt2[] PROGMEM = "Contrast";
const char txt3[] PROGMEM = "Helligkeit";
 
const  char *MENU[] PROGMEM = { txt1,txt2,txt3};


....
 
  for(int i=0,j=0;i<sizeof(MENU)/sizeof(*MENU);i++)
  {
    write_str_p( (char*)pgm_read_word( &MENU[i] ), 5, j+=10, WHT, RED );
  }

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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.