Forum: Compiler & IDEs string Konstanten mit fprintf ausgeben


von Ein Fest a. (einfest_a)


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.
1
const char Zeile1Menu00[] PROGMEM = "Test";
2
fprintf(stderr, Zeile1Menu00);

Kann mir jemand helfen?

Danke schon mal!

von Karl H. (kbuchegg)


Lesenswert?

Ein Fest a. schrieb:

>
1
> const char Zeile1Menu00[] PROGMEM = "Test";
2
> fprintf(stderr, Zeile1Menu00);
3
>

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.

von Ein Fest a. (einfest_a)


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ß

von Oliver (Gast)


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

von Karl H. (kbuchegg)


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:
1
void lcd_string( const char* s )
2
{
3
  while( *s )
4
    lcd_char( *s++ );
5
}

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
1
void lcd_string_P( const char* s )
2
{
3
  char c;
4
5
  while( ( c = pgm_read_byte(s++) ) != '\0' )
6
    lcd_char( c );
7
}

(Das hinten angestellte _P kennzeichnet die Funktion als eine, die mit 
dem Flash umgehen kann).

von Vlad T. (vlad_tepesch)


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.
1
void fun(const char* str);
2
void fun_p(const char* pstr);
3
#define fun_P(x) fun_p(PSTR(x))
4
5
const char PROGMEM str1[]="hallo";  // erzeugt Flashkonstante
6
7
fun("hallo"); // legt Kosntante im Datensegment (+flash) an
8
9
fun_p(str1);  // benutzt flashkonstanten
10
11
fun_p("hallo2");  // legt constante im Datensegment (+flash) an
12
                  // --> fun_p liefert müll
13
14
fun_P("hallo3");  // sorgt dafür, dass hallo3 als flashkosntante angelegt 
15
                  // wird und ruft fun_p mit der kosntante auf
16
17
// vorsicht:
18
// anders als folgendes, wo nur ein "hallo" angelegt wird
19
fun("hallo");
20
fun("hallo");
21
fun("hallo");
22
23
// legt folgendes 3 konstanten an.
24
fun_P("hallo3");
25
fun_P("hallo3");
26
fun_P("hallo3");
27
28
// besser ist bei mehrmaliger Verwednung also das explizite
29
// Anlegen und Benutzen der _p-Version

von Ein Fest a. (einfest_a)


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ß

von Karl H. (kbuchegg)


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.

von Ein Fest a. (einfest_a)


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!

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.