Forum: Mikrocontroller und Digitale Elektronik Problem mit PROGMEM, structure und string kombination


von Stefan F. (stefan1987)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe ein Problem mit meinem Menü. Ursprünglich war ein Menüpunkt in 
einer Structure gespeichert (Text als String, Funktion die aufgerufen 
wird, int der den aktiven Punkt indiziert) Um Platz im RAM zu sparen 
wollte ich die Strings die jeweils ausgegeben werden sollen in den 
Flashspeicher verlagern. Das hat auch soweit geklappt. Wenn ich zum 
Beispiel einen solchen String wieder ausgeben wollte konnte ich das mit

    char buffer[10];
    for (unsigned char i = 0; i <4; i++)
    {
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(MainMenu[i])));
        LCD_STRING (buffer,0,i);
    }

machen. Wenn ich nun allerdings versuche dieses Konstrukt in die 
Menupunkt Ausgabe zu integrieren kommt garnichts auf dem LCD an.
Ich habe mal den gesamten SourceCode mit angehängt, wobei die relevanten 
Files wohl PrintMenu.c und MainMenu.c sind. Der Aufruf geschieht in 
Moodlight204112.c.
Ich wäre sehr dankbar wenn mir jemand sagen könnte was ich falsch mache 
bzw falsch verstanden habe.
Vielen Dank schonmal.

Grüße Stefan

von Uwe (de0508)


Lesenswert?

Hallo,

Stefan Friedrich schrieb:
> pgm_read_word(&(MainMenu[i]))

wenn Du diese Frage beantworten kannst, bist Du ein Stück weiter:

wie viele Bytes werden pro Aufruf gelesen ?

von Stefan F. (stefan1987)


Lesenswert?

Danke schonmal für die schnelle Antwort.
Also wenn ich das richtig verstanden hab wird hier nur die Adresse des 
Strings weitergegebn. Und gelesen wird hier ein Word also 2 Byte.
Soviel ich weiß sollte das auch passen da die Adresse 16 Bit hat.
Und wenn ich diese Funktion nutze funktioniert das auch. Also:

char string_1[] PROGMEM = "Program";
char string_2[] PROGMEM = "Options";
char string_3[] PROGMEM = "Time";
char string_4[] PROGMEM = "Help";


PGM_P MainMen[] PROGMEM =
{
    string_1,
    string_2,
    string_3,
    string_4
};

void main(void)
{
    char buffer[10];

    for (unsigned char i = 0; i <4; i++)
    {
        strcpy_P(buffer, (PGM_P)pgm_read_word(&(MainMen[i])));

       LCD_STRING (buffer,0,i);
    }
    return;
}

Das hier funktioniert einwandtfrei.
Also denk ich mal das ich irgendwas falsch gemacht hab bei der DrawMenu 
oder DoMenu Funktion.

von Karl H. (kbuchegg)


Lesenswert?

Im übrigen ist es nicht besonders schlau, wenn du zuerst den kompletten 
String ins SRAM kopierst um dann eine vorhandene Ausgabefunktion 
aufzurufen. Es ist wesentlich vernünftiger, wenn du dir eine 2-te String 
Ausgabefunktion baust, die den String Zeichen für Zeichen eben nicht aus 
dem SRAM sondern aus dem Flash holt.

Aber überarbeite erst mal deine LCD_STRING Funktion!
1
void LCD_STRING (char *s,int x, int line)
2
  {
3
    switch (line)
4
    {
5
    
6
    case 0:
7
    {
8
      LCD_GOTO_XY(x,line);
9
      while (*s)
10
      {
11
        LCD_DATA1 (*s);
12
        s++;
13
      }
14
      break;
15
    }
16
    case 1:
17
    {
18
      LCD_GOTO_XY(x,line);
19
      while (*s)
20
      {
21
        LCD_DATA1 (*s);
22
        s++;
23
      }
24
      break;
25
    }    
26
    case 2:
27
    {
28
      LCD_GOTO_XY(x,line);
29
      while (*s)
30
      {
31
        LCD_DATA2 (*s);
32
        s++;
33
      }
34
      break;
35
    }
36
    case 3:
37
      LCD_GOTO_XY(x,line);
38
      while (*s)
39
      {
40
        LCD_DATA2 (*s);
41
        s++;
42
      }
43
      break;
44
    }    
45
  }

Die Funktion ist mehr als ungeschickt gemacht und viel zu lang, für das 
was sie kann.

Merke: Bau dir Basisfunktionen, die du gut benutzen kannst und viele 
Probleme auf höherer Softwareebene sind plötzlich keine Probleme mehr.

von Karl H. (kbuchegg)


Lesenswert?

Ooops

Geh das mal mit einem Wert für MenuSize von 4 durch
1
void DrawMenu( uint8_t MenuSize, struct MenuEntry Menu[],PGM_P Strings[] )     // Display the Menu Entries
2
{
3
  char buffer[25];
4
  uint8_t i=0;
5
  LCD_CLEAR();
6
  
7
  if (MenuSize <4)                  // less then 4 entries in this menu ?
8
  {
9
***** nicht der Fall           ....
10
  }
11
  
12
  if (MenuSize >3 && MenuSize <8)      // more then 4 and less then 8 entries ?
13
  {
14
15
***** passt: MenuSize > 3
16
17
  LCD_CLEAR();
18
  for( i = 4; i < (MenuSize); ++i )            // loop until last entry reached
19
    {
20
21
***** Wie oft wird diese Schleife ausgeführt, wenn MenuSize einen Wert von 4 hat?
22
23
...


PS:
Warum hast du eigentlich den String Pointer nicht gleich in dein struct 
MenuEntry mit aufgenommen? Da mit einem zusätzlichen Pointer Array zu 
hantieren ist nur eine zusätzliche Fehlerquelle mehr.

von Stefan F. (stefan1987)


Angehängte Dateien:

Lesenswert?

Das war das Problem. Danke für die schnellen Antworten.
Ich hab den Source Code nochmal angehängt falls jemand sowas brauchen 
kann.
Ausserdem habe ich auch versucht die Stringpointer in die Structure mit 
reinzupacken allerdings hat das nicht funktioniert.
Hab ich den Absatz falsch verstanden ? Oder nur falsch umgesezt ?

->PS:
->Warum hast du eigentlich den String Pointer nicht gleich in dein 
struct
->MenuEntry mit aufgenommen? Da mit einem zusätzlichen Pointer Array zu
->hantieren ist nur eine zusätzliche Fehlerquelle mehr.

Der neue Source ist auch im Anhang. Wäre super wenn jemand nochmal 
drüber schauen könnte.
Vielen Dank schonmal.

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.