F() -Funktion für Ausgabe über Ethernet

Hi,
arbeite zwar momentan mit einem Mega als Webserver, aber da ist der Speicher auch nicht unbegrenzt.
Da ich eine HTML-Seite über Ethernet sende, und nur noch ca. 1000Byte RAM übrig sind, hab ich angeregt von Serenifly über Auslagerung ins Flash nachgedacht.
Für die F()-Funktion hab ich zwar nur Beispiele für Serial.println gefunden, aber ich dachte mir ich probiers auch mal mit client.println.
Allein der Header der HTML-Seite hat mir schon 60Byte an SRAM gebracht. :slight_smile: Aber 106 Byte an Flash gekostet?? Na ja, davon hab ich noch genug.

client.println(F("HTTP/1.1 200 OK"));
client.println(F("Content-Type: text/html"));
client.println(F("Connnection: close"));
client.println();

Würdet ihr das auch so machen, oder gibts noch bessere Ideen?

Allerdings klappt es nicht immer. Ich hab auch dynamische Zeilen, bei denen ich Werte in den HTML-Code integriere.

client.println(F("objGradient.addColorStop(1,   'rgb" + temp6 + "');"));

Hier ist temp6 ein C-String. Da klappt es leider nicht. Fehlermeldung:
initializer fails to determine size of ‘__c’
Oder auch hier, selbe Fehlermeldung:

sprintf (timestring, "%02d:%02d:%02d", hour, minute, second) ; 
client.println(F("<tr><td colspan='3'>Aktuelle Uhrzeit: " + String(timestring) + " Uhr</td></tr>"));

Gibts da auch eine Lösung?

Gruß/hk007

Du kannst das F()-Makro nur für konstante C-Strings verwenden und dort gibt’s den ‘+’-Operator nicht. Wenn Du das optimieren willst, kannst Du die p_strdup-Funktion verwenden, aber vergiss die schreckliche String-Klasse, die leider immer noch in der Arduino-IDE ihr Unwesen treibt.

So oder so brauchst du RAM um den String zusammenzubasteln. Man kann auch Strings mit strcpy_P aus dem Flash kopieren und dann mit strcat_P mit anderen Strings im Flash verknüpfen. Aber man braucht dafür einen RAM Puffer. Lediglich wenn der String komplett im Flash ist, kann man ihn ganz an eine Funktion übergeben, die diesen Byte-weise ausliest.

Kann man bei Ethernet print() und println() kombinieren, oder muss das immer eine ganze Zeile auf einmal sein? Laut Doku gibt es auch print(): http://arduino.cc/en/Reference/ClientPrint Dann kann man vielleicht den konstanten Teil mit F() verpacken und den Variablen Teil normal dazwischen. Lediglich die letzte Anweisung muss dann println() sein.

Ja, client.print() verwende ich auch bei der Ethernet-Ausgabe.

Und du hast recht, man könnte die Zeilen auch trennen:

//client.println("objGradient.addColorStop(0,   'rgb" + temp1 + "'); ");                        
-->
client.print("objGradient.addColorStop(0,   'rgb");
client.print(temp1);
client.println("'); ");

Ist das selbe Ergebnis: Und dann die erste und die letzte mit dem F() versehen. Aber da geht mir etwas an Lesbarkeit des HTML-Textes verloren.

Ich hab jetzt alle "normalen" Zeilen der Webseite ins Flash verbannt, und bin dadurch von 1288 auf 4678 Byte freies RAM gekommen. :) :) :) Das ist m.E. mit wenig Aufwand ein super Ergebnis.

Noch eine Frage: Bei der detaillierten Ausgabe des Compilers bekomme ich für jede Zeile mit dem F() Makro eine Warnung:

warning: only initialized variables can be placed into program memory area

Muss ich mir da Gedanken machen? Ich hab ja keine Variablen, sondern nur Text.

Du hast schon eine Art Variable. Die im PROGMEM ist. Da läuft einiges im Hintergrund das du nicht siehst. Das ist ein Bug in AVR-gcc der ignoriert werden kann. Arduino benutzt leider eine Uralt Version davon wo das noch nicht gepachtet ist :(

Es gibt eine Anleitung um da ein Update zu machen, aber das hat bei mir nicht funktioniert. Anscheinend muss man da auf dem Mega mehr als auf dem UNO anpassen.

OK, danke für die Info. Muss schon sagen, dass du ein fundiertes Hintergrundwissen hast.

Danke nochmal. Bis zum nächsten Problem :P