www.mikrocontroller.net

Forum: GCC string Konstanten mit fprintf ausgeben


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Ein Fest a. (einfest_a)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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!

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

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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.

Autor: Ein Fest a. (einfest_a)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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ß

Autor: Oliver (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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

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

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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).

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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

Autor: Ein Fest a. (einfest_a)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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ß

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

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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.

Autor: Ein Fest a. (einfest_a)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
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!

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




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 erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net