Forum: Compiler & IDEs Zugriff string Konstante im PROGMEM eleganterer, einfacherer Weg?


von AVRli (Gast)


Lesenswert?

Hi!

Nun wird mein SRAM langsam knapp und ich muss meine String Konstanten in 
den PROGMEM verschieben. Derzeit behelfe ich mir so, das geht doch gibt 
es einen eleganteren Weg?
1
void get_id_name(uint8_t id, char *out) {
2
  static char strA[] PROGMEM = "Alfons";
3
  static char strB[] PROGMEM = "Julia";
4
  static char strC[] PROGMEM = "Seb";
5
  static char strD[] PROGMEM = "Olaf";
6
  static char strE[] PROGMEM = "unknown";
7
8
  switch (id) {
9
    case 0: copy_pgmstr_to_ram(strA, out); break;
10
    case 1: copy_pgmstr_to_ram(strB, out); break;
11
    case 2: copy_pgmstr_to_ram(strC, out); break;
12
    case 3: copy_pgmstr_to_ram(strD, out); break;
13
    case 4: copy_pgmstr_to_ram(strE, out); break;
14
  }
15
}

Ich brauche also zu der ID dann einen Zeiger auf die Zeichenkette.
Meine Versuche mit einer direkte Deklaration eines Array funktioniert 
nicht.

Danke für jeden Tip!

Gruß AVRli...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Guck dir mal den PSTR-Makro an.

von Laszlo H. (mobius)


Lesenswert?

Erspart dir den char PROGMEM Teil. Eleganter (und schneller) geht es, 
indem du die Zeiger auf die einzelnen Strings in ein Array packst.
1
static char strA[] PROGMEM = "Alfons";
2
static char strB[] PROGMEM = "Julia";
3
static char strC[] PROGMEM = "Seb";
4
static char strD[] PROGMEM = "Olaf";
5
static char strE[] PROGMEM = "unknown";
6
7
static char strings[] = {
8
  strA,
9
  strB,
10
 ...
11
};
12
13
void get_id_name(uint8_t id, char *out) {
14
  strcpy_P(out, &(strings[id]);
15
}

Logischerweise kannst du auch diesen in den PROGMEM legen. Spart dir 
dann je 2 Byte/Eintrag, nur musst du dann vorher auch diesen aus dem 
Flash lesen, siehe [1].

gruß
Mobius

[1] http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

von AVRli (Gast)


Lesenswert?

Hallo!

Danke für Eure Hinweise.
Ich habe mich nun an das Beispiel gehalten aber das sorgt nun dafür das 
mein Programm nun überhaupt nicht mehr anläuft. :-(

Das wird nun aber auch so in [1] beschrieben.

Ob ich das mit den Zeigern jemals verstehen werde??? :-(

Gruß AVRli...
1
void get_id_name(uint8_t id, char *out) {
2
3
char string_1[] PROGMEM = "String 1";
4
char string_2[] PROGMEM = "String 2";
5
char string_3[] PROGMEM = "String 3";
6
char string_4[] PROGMEM = "String 4";
7
char string_5[] PROGMEM = "String 5";
8
9
PGM_P string_table[] PROGMEM = 
10
{
11
    string_1,
12
    string_2,
13
    string_3,
14
    string_4,
15
    string_5
16
};
17
18
    strcpy_P(out, (PGM_P)pgm_read_word(&(string_table[id])));
19
}

von Stefan E. (sternst)


Lesenswert?

Deine Strings stehen so ja auch gar nicht im Flash (und die 
Pointer-Liste auch nicht). Du bekommst doch auch garantiert "attribute 
ignored"-Wanungen vom Compiler. Entweder schreibst du noch ein static 
davor, oder du machst globale Variablen daraus.

PS: Und für die Zukunft merken: Warnungen nicht einfach ignorieren, und 
bei Fragen hier mit angeben.

von Karl H. (kbuchegg)


Lesenswert?

Mir ist nicht klar, warum du nicht den allereinfachsten Weg gehst
1
void get_id_name(uint8_t id, char *out) {
2
  switch (id) {
3
    case 0:  copy_pgmstr_to_ram(PSTR( "Alfons" ),  out); break;
4
    case 1:  copy_pgmstr_to_ram(PSTR( "Julia" ),   out); break;
5
    case 2:  copy_pgmstr_to_ram(PSTR( "Seb" ),     out); break;
6
    case 3:  copy_pgmstr_to_ram(PSTR( "Olaf" ),    out); break;
7
    default: copy_pgmstr_to_ram(PSTR( "unknown" ), out); break;
8
  }
9
}

Das PSTR Makro sorgt dafür, dass der String ins Flash verbannt wird.

von AVRli (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Mir ist nicht klar, warum du nicht den allereinfachsten Weg gehst

Ja mir wohl auch nicht. :-(
Das ist wirklich ein sehr interessanter Weg! :-D
So konnte ich ohne viel deklarieren meine ganzen Zeichenkette in den 
PROGMEM legen. Gut die ganzen str Funktionen müssen dann natürlich die 
mit _P sein das war aber nicht so schwer.

Satte 30% hab ich im RAM mit Zeichenketten "verballert". Nun im 
Programmspeicher ist noch genügend Platz, auf Geschwindigkeit kommt es 
bei der Anwendung nicht an.

Und nebenbei meine Funktion
1
copy_pgmstr_to_ram(PSTR( "Alfons" ),  out);

Gibt es ja auch schon, ach wenn man nicht immer das Rad neu erfinden 
würde wollen. Gut ich hab was bei gelernt aber die folgende nehme ich 
nun. ;-)
1
strcpy_P(out, PSTR( "Alfons" );


Danke!
Gruß AVRli...

von Falk B. (falk)


Lesenswert?

@AVRli (Gast)

>Satte 30% hab ich im RAM mit Zeichenketten "verballert". Nun im
>Programmspeicher ist noch genügend Platz, auf Geschwindigkeit kommt es
>bei der Anwendung nicht an.

Aus dem RAM lesen dauert beim AVR 2 Takte (ld), aus dem Flash 3 Takte 
(lpm). Plus den ganzen Schleifenoverhead ist beides annähernd gleich 
schnell.

MfG
Falk

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Ist es denn für Deine Anwendung überhaupt erforderlich, daß die Strings 
ins RAM kopiert werden? Was machst Du dann dort mit den Strings?

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.