Problem mit Stringlänge

Hallo,

ich sende mit dem Arduino Mega 2560 mit Ethernet-Shield per POST einen String. Das funktioniert grundsätzlich. Die Übertragung findet minütlich statt und bleibt im Heimnetzwerk.

Mit der Länge des Strings gibt es aber Probleme. Länge 993 geht einwandfrei. Bei Länge 1193 erfolgt die erste Übertragung nach Start des Scrips korrekt, bei jeder weiteren Übertragung werden nur die letzten ca. 40 Zeichen gesendet ins Netz und auch an die Konsole. Ich vermute deshalb, dass der String eine Begrenzung hat. Stimmt das? Gibt es Abhilfe?

Ich füge den Codeausschnitt bei:

// String bilden
    // Zeit
        sStr = sStr + "B" + sNr + "=zeit_ardu";
        sStr = sStr + "&W" + sNr + "=" + t;        // bzw. client.print(strDatumUhrzeit);
    // Daten
        for (k = 0; k < AnzahlSensoren; k++) { // Schleife über Sensor-Array
            sNr = ++sNr;
    // Temp
            sStr = sStr + "&B" + sNr + "=" + sensorList[k].bez + "T";     // T = Temp
            sStr = sStr + "&W" + sNr + "=" + sensorList[k].isttemp;     // Temperatur
    // Soll+Digi für Raum
            if (k < AnzahlMitSoll) {
    // Soll
                sNr = ++sNr;
                sStr = sStr + "&B" + sNr + "=" + sensorList[k].bez + "S";     // S = Soll
                sStr = sStr + "&W" + sNr + "=" + sensorList[k].solltemp;     // Solltemperatur
    // Digi Achtung Pin-Logic !s.o.
//                sNr = ++sNr;
//                sStr = sStr + "&B" + sNr + "=" + sensorList[k].bez + "D";     // D = digi
//                sStr = sStr + "&W" + sNr + "=" + !sensorList[k].digi;     // digi = Schaltausgang
            } // Ende if AnzahlMitSoll
        } // Ende for AnzahlSensoren

// Verbindung
        if (!client.connect(server_wolke, 80)) {
            Serial.println(F("-> keine Verbindung zum Server"));  // only use serial when debugging
        } 
        else client.stop();
        if (client.connect(server_wolke, 80)) {             // TRUE => connection

// An Wolke senden
            client.print("POST /");
            client.print(strphpDatei);        // php-Datei
            client.println(" HTTP/1.1");
            client.print("Host: ");
            client.println(server_wolke);
            client.println("User-Agent: Arduino/1.0");
            client.println("Connection: close");
            client.println("Content-Type: application/x-www-form-urlencoded;");
            client.print("Content-Length: ");
            client.println(sStr.length());
            client.println();
            client.println(sStr);
            #ifdef STRING
                Serial.print(sStr);
                Serial.print(F(" -> "));
                Serial.println(sStr.length());
            #endif
//            client.println(F("Connection: close"));
            client.println();
            client.stop();
        } // Ende if client.connect
        else {
            Serial.println(F("--> connection failed !!"));  // no connection to the server
        } // Ende else client.connect

Gruß Gerd

gerd-wolfgang:
Ich vermute deshalb, dass der String eine Begrenzung hat. Stimmt das? Gibt es Abhilfe?

Die Begrenzung für dynamisch angelegte 'String-Objekte' ist der begrenzte RAM-Speicher des Controllers, wie stark Du diesen durch Verwendung dieser 'String-Objekte' im Verlauf des Programms fragmentierst, und ob zum Zeitpunkt der Verwendung noch ein RAM-Stück frei ist, das groß genug ist um das String-Objekt aufzunehmen.

Die simpelste Abhilfe für Programmierer, die unbedingt mit 'String-Objekten' programmieren und dabei reichlich RAM verbrauchen möchten ist: Ein Arduino-Board mit MEHR RAM kaufen und verwenden! Also wenn ein UNO nicht reicht, auf einen MEGA umsteigen. Wenn ein MEGA nicht reicht, dann einen DUE verwenden.

Die andere Alternative wäre:

  • Programmieren lernen
  • 'String-Objekte' strikt vermeiden und nur mit C-Strings arbeiten
  • und dabei keine 'Riesen-Strings' auf einmal im Speicher halten, sondern stets nur kleine String-Puffer verwenden

Danke für die Belehrung.

Ich versuche aus der Antwort für mich etwas positives ziehen. Kann es sein, dass, wenn ich den String teile, das Ganze funktionieren könnte?
Der Grund für die Stringbildung war, dass die Übertragung per POST die Anzahl der Zeichen benötigt. Da war für mich der String naheliegend. Nur macht er beschriebene Probleme. OK. Und jetzt suche ich einen Ausweg, einen anderen Lösungsweg, um es besser zu machen. Deshalb schreibe ich, um zu lernen.

Bisher hat mir dieses Forum immer geholfen, und dafür bin ich sehr dankbar.

Gruß Gerd

  1. Möglichkeit ist Arduino MEGA mit zusätzlich RAM ausstatten zB Upgrading RAM In An Arduino Mega | Hackaday

Es ist egal ob Du einen String hast oder 2 mit der halben Größe. Der Speicherbedarf bleibt gleich.

Grüße Uwe

gerd-wolfgang:
Der Grund für die Stringbildung war, dass die Übertragung per POST die Anzahl der Zeichen benötigt. Da war für mich der String naheliegend. Nur macht er beschriebene Probleme. OK. Und jetzt suche ich einen Ausweg, einen anderen Lösungsweg, um es besser zu machen. Deshalb schreibe ich, um zu lernen.

Auch wenn Du bei Deinen zwar programmtechnisch schrottigen, aber von Dir offenbar dennoch heißgeliebten String-Objekten bleiben möchtest, kannst Du Dir natürlich einen Algorithmus und eine Funktion überlegen, die
a) mit sehr viel weniger RAM auskommt weil sie
b) nicht den gesamten String auf einmal im RAM halten muss sondern
c) den String zusammenstückelt

Du müßtest Dir nur eine Two-Pass-Funktion machen, die zweimal läuft und mit einem Parameter gesteuert verschiedene Aufgaben erledigen kann:

  • Pass-1: Nur die Länge zusammenzählen
  • Pass-2: Die Zeichen tatsächlich ausgeben

Beispiel für die Verarbeitung von konstanten Texten, int, long und vorformatierten C-String Puffern:

int string2client(EthernetClient &client, boolean send)
{// bei send==true wird gesendet
  // bei send==false wird nur gezählt
  int count=0;
  if (send) client.print("B"); // konstanter Text
  count+= strlen("B");
  if (send) client.print(sNr); // Integer oder long Wert
  count+= String(sNr).length(); // keine Ahnung, ob das mit dem "String" so richtig ist
  if (send) client.print("=zeit_ardu");  // konstanter Text
  count+=  strlen("=zeit_ardu");
  if (send) client.print(t); // vorformatierter Stringpuffer
  count+=  strlen(t);
  return count;
}

Um nur die Ausgabelänge zu zählen und NICHT zu senden wäre der Aufruf dann sowas wie:

  int strLen=string2client(NULL, false);
  oder
  int strLen=string2client(client, false);

Und um den String in einem zweiten Pass zu senden wäre der Aufruf dann sowas wie:

  string2client(client, true);

Da zu keinem Zeitpunkt der vollständige "lange String" im RAM gehalten werden braucht, sinkt durch dieses Two-Pass-Verfahren aus Zählen und Senden der RAM-Bedarf im Sketch drastisch.

Du müßtest dabei nur aufpassen, dass Du jeweils die richtigen Längen zählst, abhängig davon, was Du ausgibst (int, long, float, String-Objekt, C-String), so dass gezählte Stringlänge keine Abweichung zu den gesendeten Zeichen aufweist.

Danke. Ich gehe mal auf Tauchstation, werde den RAM-Bedarf reduzieren und "Stringlänge" separat berechnen.
Gruß Gerd

Oder du machst es umgekehrt und weisst vorher, wie lang der String werden wird.
Und sendest dann eben soviel wie versprochen.


Die Arduino String Klasse kann nicht viel.
Am besten wäre, sie hätte auch den + Operator nicht.

client.print("POST /");

sparst Du RAM indem Du bei Ausgabe von Text das F-Makro verwendest:

client.print(F("POST /"));