Hallo,
ich habe ein größeres Programm und möchte sämtliche Strings im Flash
ablegen. Allerdings möchte ich eine gemeinsam benutze Datei mit Texten
schreiben, auf die von verschiedenen C-Files zugegriffen werden kann.
Ich habe schon ein paar Texte im Flash und es geht auch problemlos,
allerdings geht das Speichern der Strings im Flash anscheinend nur in
C-Files und nicht in H-Files.
Optimal für mich wäre eine Datei mit Zuordnung zwischen Zahl (ID) und
Text im Flash, z.B.:
1: "ABC"
2: "Test abc"
3: "Test 123"
4: "Displaybeleuchtung mit Bargraph waehlen."
Beim Aufruf einer Funktion mit übergebener ID sollte dann der Text aus
dem Flash in einem String zurück gegeben werden. So in etwa:
// Übergabewerte: ID und Adresse für den rückzuliefernden String
void text_aus_flash_holen(unsigned int uiTextID, char* caString)
{
strcpy_P(caString, xxx); // xxx müßte irgend wie die ID sein
return;
}
Habe aber keinen Plan, wie ich die Strings mit der dazugehörenden ID
abspeichern muß und später abrufen kann...
hab es so ausprobiert und folgenden Aufruf gemacht:
text_aus_flash_holen(2, caText_temp);
Es kommt auch ein Text, aber ein falscher ("ext"). Irgend etwas ist noch
nicht korrekt mit dem Zeiger auf den Flash...
-------------------------
Auch die zweite Version (editiert vom Benutzer) geht nicht. Es wird 0x00
zurück geliefert (also Text gefunden), jedoch der falsche Text aus
irgend einer Stelle im Flash...
Stringtabelle (ebenfalls im Flash) und Leseroutine ist dann hier schon
beschrieben:
Beitrag "Re: RTTTL Player"
Die Funktion liefert den PGM_P mit der Stringadresse[index], der dann
der funktion strcpy_P() als Quellzeiger übergeben werden kann.
Martin M. schrieb:> Hab es nun so gemacht, aber der Compiler meckert. Ich denke ich> habe etwas falsch verstanden.
Da kannste froh sein, dass ich kein Compiler bin..
Schau Dir das hier mal an..
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Strings
dort wird das Prinzip für die Stringablage im Flash erläutert.
Erstmal - die Zeilen mit Deinen Texten sind ja unterschiedlich lang;
dann - für den Compiler steht da nur ein einziger String (mit mehreren
Zeilen) - also funktioniert das da oben so nicht.
Du musst dem Compiler sagen - diese Zeile ist der String1, diese Zeile
ist der String2 usw. - und ausserdem, wolltest Du die Strings nicht auch
im Flash ablegen?!
1
constcharstring1[]PROGMEM={"ABC"};
2
constcharstring2[]PROGMEM={"Test abc"};
3
constcharstring3[]PROGMEM={"Test 123"};
4
constcharstring4[]PROGMEM={
5
"Displaybeleuchtung mit Bargraph waehlen."
6
};
Die Strings sind aber alle unterschiedlich lang. Die Auswahl über
String[index] funktioniert aber nur, wenn alle Elemente / Strings die
gleiche Länge haben. Also brauchst Du noch eine Tabelle mit konstant
langen Elementen; hierfür bieten sich die Anfangsadressen Deiner Strings
an.
1
constchar*PROGMEMconststrings[]={
2
string1,string2,string3,string4
3
};
So - und um nun den String[index] aus dem Flash zu lesen, musst Du
zuerst in der Tabelle schauen, an welcher Adresse der steht, und dann
den String ab dieser Adresse kopieren.
Alle Strings landen im "Flash". Immer, sonst würde der Controller die ja
vergessen. Falls ein spezieller "UserFlash" gemeint ist, müssen die
Strings mit dem entsprechenden Pragma markiert werden, damit die an die
entsprechenden Adressen geschrieben werden.
Dei den meisten MuC funktioniert schon:
const char string[x] = "Blahblubb"
und dann einfach auf den String per Variable zugreifen. Bei der
Konstruktion funktioniert auch sizeof().
Das "PROGMEM" Pragma brauchts nur für (einige) Atmels.
Luxuriös wirds, wenn man noch einen Zeilenumbruch (oder 0x00) dranhängt,
um ggf eine Fehlerbehandlung für Ausgaben zu bekommen.
Aber was der OP mein ist:
Alle diese "strings" in einer zentralen '.h'+'.c'- Datei verpacken, und
entsprechend regulär includieren. Dann können alle Module sauber per
Variablenname darauf zugreifen.
Martin M. schrieb:> Hab es nun so gemacht, aber der Compiler meckert. Ich denke ich habe> etwas falsch verstanden.
Das ist aber echt schade, daß der Compiler nur "mecker" ausgibt, statt
eine Beschreibung, die auf den Fehler hinweisen könnte und eine
Zeilennummer.
Roland E. schrieb:> Alle Strings landen im "Flash". Immer, sonst würde der Controller die ja> vergessen.
Naja, beim AVR landen die Strings ohne weiteres Zutun im RAM, aber der
muss ja irgendwie intialisiert werden. Der Initialisierungswert ist also
im Flash gespeichert, die eigentliche Stringvariable aber ist im RAM.
> Das "PROGMEM" Pragma brauchts nur für (einige) Atmels.
Konkret die AVRs, um die es offenbar geht, denn strcpy_P() gibt's meines
Wissens auch nur dort.
> Luxuriös wirds, wenn man noch einen Zeilenumbruch (oder 0x00) dranhängt,> um ggf eine Fehlerbehandlung für Ausgaben zu bekommen.
0x00 (bzw. '\0') wird sowieso schon automatisch angehängt. Das ist die
"Natur" eines Stings in C. Was das mit Fehlerbehandlung zu tun hat,
verstehe ich aber nicht.
Wenn ich eine Variable mit
const char string[] = "Irgendwas"
anlege, ist die nicht Nullterminiert. Das ist bei C auch völlig normal.
Das die dann aus dem Flash als Ganzes in den Ram geholt wird, ist ein
AVR-spezifisches Problem.
Die "Fehlerbehandlung" ist durch den Programmierer zu implementieren,
wenn der auf die Daten wie oben beschrieben per eigenen Zeiger losgeht.
Er sieht nämlich sonst nicht, wo sein String zu Ende ist.
Zugegeben, ich hatte mich mit AVR nur am Rande beschäftigt. Es gibt
genug andere und weniger umständliche Plattformen...
Roland E. schrieb:> Wenn ich eine Variable mit>> const char string[] = "Irgendwas">> anlege, ist die nicht Nullterminiert. Das ist bei C auch völlig normal.
Nein, Stringliterale sind in C automatisch nullterminiert.