Datum:
Hallo, für ein mehrsprachiges Menü möchte ich die Menüeinträge der jeweiligen Landessprache in string konstanten im Flash speichern, und sie je nach gewählter Sprache mit fprintf auf dem Display ausgeben. Ich habe schon herausgefunden, dass es so nicht funktioniert: Es gibt zwar keinen Compiler-Fehler, aber es wird auch nichts ausgegeben.
const char Zeile1Menu00[] PROGMEM = "Test"; fprintf(stderr, Zeile1Menu00); |
Kann mir jemand helfen? Danke schon mal!
Datum:
Ein Fest a. schrieb: >
> const char Zeile1Menu00[] PROGMEM = "Test"; > fprintf(stderr, Zeile1Menu00); > |
fprintf kann mit dem String im Flash nichts anfangen. * Lad ihn dir zuerst in ein Zwischenarray im SRAM und gib dann von dort aus. * anstelle von fprintf kannst du fprintf_P benutzen. Das holt sich den Formatstring aus dem Flash. Aber warum eigentlich der komplizierte Weg über fprintf? Eine Stringausgabe direkt aus dem Flash aufs Display ist doch viel einfacher. Ausser sprintf kann man auf einem AVR die Standard-I/O Funktionen meistens nicht besonders sinnvoll nutzen. Das zeigt sich schon dadurch, dass die einen Ausgabestrom, der eigentlich zur Ausgabe von Fehlermeldungen gedacht ist, als Ausgabekanal für ein Menü benutzen willst. Das passt konzeptmässig nicht wirklich gut zusammen.
Datum:
Vielen Dank für die nächtliche Antwort! Mit fprintf_P funktioniert es. Ich bin noch recht neu auf dem Gebiet der AVR-Programmierung, und muss zugeben, dass ich die Implementierung/Initialisierung meines Displays einfach aus der Codesammlung hier gemopst habe. Und da wurden Ausgaben mit fprinf gemacht... Könnest du/jemand mir genauer erklären, wie die "einfache" Variante direkt aus dem Flash aussieht? Es gibt zwar Beispiele im GCC Totorial, aber die kann ich nicht wirklich für meinen Fall übersetzen. Gruß
Datum:
printf() ruft ja auch nur deine eigene putc()-Funktion auf, um Zeichen auf das Display zu schicken. Für Zeichenketten, die ja durch printf gar nicht verändert werden, kannst du putc() daher auch direkt aufrufen, und damit die Zeichen deines Strings direkt ausgeben. Oliver
Datum:
Ein Fest a. schrieb: > Vielen Dank für die nächtliche Antwort! > > Mit fprintf_P funktioniert es. > > Ich bin noch recht neu auf dem Gebiet der AVR-Programmierung, und muss > zugeben, dass ich die Implementierung/Initialisierung meines Displays > einfach aus der Codesammlung hier gemopst habe. Und da wurden Ausgaben > mit fprinf gemacht... Wo genau? Aus dem STegreif heraus, weiß ich keinen einzigen Artikel hier am µC.Net Forum, welcher fprintf benutzt. Aber ich kenne natürlich auch nicht alle Artikel. > Könnest du/jemand mir genauer erklären, wie die "einfache" Variante > direkt aus dem Flash aussieht? Du hast eine Funktion, welche ein einzelnes Zeichen ausgibt. Ich nenn sie mal lcd_char. Daraus lässt sich leicht eine Funktion bauen, die einen String aus dem SRAM ausgibt:
void lcd_string( const char* s ) { while( *s ) lcd_char( *s++ ); } |
Soweit so gut. Jetzt soll der String aber nicht aus dem SRAM kommen, sondern aus dem Flash. Ins Flash kann man nicht so einfach mit *s zugreifen, wenn man einen Pointer auf die Daten hat, sondern man muss das durch die Funktion pgm_read_byte() ersetzen, die den Zugriff durchführt und das Byte liefert. Und genau das machen wir: Alle *s durch pgm_read_byte ersetzen, ein bischen umstrukturieren, so dass der Code einfacher wird und es kommt raus
void lcd_string_P( const char* s ) { char c; while( ( c = pgm_read_byte(s++) ) != '\0' ) lcd_char( c ); } |
(Das hinten angestellte _P kennzeichnet die Funktion als eine, die mit dem Flash umgehen kann).
Datum:
Karl Heinz Buchegger schrieb: > (Das hinten angestellte _P kennzeichnet die Funktion als eine, die mit > dem Flash umgehen kann). Die Libs die ich bisher gesehen habe, benutzen eine andere Konvention: fun_p kennzeichnet eine Funktion die mit Flashdaten umgehen kann. fun_P kennzeichnet eine Funktion (meist als Macro realisiert) die die Übergebene Kosntante auch direkt im Flash anlegt. Beispiel.
void fun(const char* str); void fun_p(const char* pstr); #define fun_P(x) fun_p(PSTR(x)) const char PROGMEM str1[]="hallo"; // erzeugt Flashkonstante fun("hallo"); // legt Kosntante im Datensegment (+flash) an fun_p(str1); // benutzt flashkonstanten fun_p("hallo2"); // legt constante im Datensegment (+flash) an // --> fun_p liefert müll fun_P("hallo3"); // sorgt dafür, dass hallo3 als flashkosntante angelegt // wird und ruft fun_p mit der kosntante auf // vorsicht: // anders als folgendes, wo nur ein "hallo" angelegt wird fun("hallo"); fun("hallo"); fun("hallo"); // legt folgendes 3 konstanten an. fun_P("hallo3"); fun_P("hallo3"); fun_P("hallo3"); // besser ist bei mehrmaliger Verwednung also das explizite // Anlegen und Benutzen der _p-Version |
Datum:
Danke für die Antworten! Damit sollte ich es hingekommen, das ganze entweder umzubauen, oder es beim nächsten "Displayprojekt"(Ist in Aussicht.) gleih so zu machen. @Karl Heinz Buchegger Weil du gefragt hast, wo ich das her habe: (Beitrag von Thilo M.(6. Eintrag)) Beitrag "Dog-M / ST7036 Routine für 1-Zeiliges Display SPI-Mode" Gruß
Datum:
Ein Fest a. schrieb: > @Karl Heinz Buchegger > Weil du gefragt hast, wo ich das her habe: (Beitrag von Thilo M.(6. > Eintrag)) > Beitrag "Dog-M / ST7036 Routine für 1-Zeiliges Display SPI-Mode" Ah. ok. Na ja. Das ist ja kein Tutorial. Die Tutorien finden sich hier AVR-GCC-Tutorial AVR-Tutorial Die dort verwendeten LCD sind zwar keine per SPI angesteuerten, aber die grundsätzliche Vorgehensweise für höherwertige Funktionalität (also die SChichten über lcd_char) kann man sich ja trotzdem ansehen.
Datum:
Hallo, dann hast du mich etwas falsch verstanden. Ich hatte das Caodebeispiel und das Tutorial in zwei verschiedenen Zusammenhängen erwähnt. Das Codebeispiel habe ich zur Vorlage genommen, und im Tutorial habe ich Beispiele zu String-Operationen aus dem Flash gefunden, wobei es mir nicht gelungen ist die erwähnten Beispiele auf meinen Fall zu übertragen. Danke nochmal!