Nano startet neu, wenn Sketch "länger" ist.

Hallo

Meinen Arduino Nano soll Messwerte von 2 Sensoren abholen und per Http-Request an einen Server schicken.
Das Auslesen der Sensoren alleine funktioniert, das Senden der Daten von einem Sensor (egal Welcher) ebenfalls.
NUR alles zusammen funktioniert nicht.

Das Programm startet immer wieder neu, mit verstümmelter serieller Ausgabe.

Auf einem Arduino Mega 2560 funktioniert das Programm (2 Sensoren + Senden) allerdings.

Kann es sich um Speicherüberlauf handeln?
Was muss man besser machen, damit es mit beiden Sensoren auch auf den Nano läuft?

Zum Anhang:
Das Programm wie angehängt funktioniert (Sensor SDS011 auskommentiert) und hat folgende Größe.

DATA: [======= ] 65.7% (used 1345 bytes from 2048 bytes)
PROGRAM: [========= ] 89.0% (used 27356 bytes from 30720 bytes)

Auch mit allen Zeilen (auch Debug) sind es weniger als 100%.
(Das Problem ist IDE unabhängig.)

Vielen Dank & Viele Grüße

main.cpp (3.87 KB)

Was oll das für ein Programm sein, das du angehängt hast ?
Ein Arduino arbeitet üblicherweise mit einer Ino-Datei.

Diese kannst du hier posten und das wie üblich in Code-Tags.

Hier Code direkt.

//#include <Arduino.h>
#include <SPI.h>
#include <HttpClient.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <SdsDustSensor.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

int rxPin = 2; // 11 mega
int txPin = 3; // 12 mega
SdsDustSensor sds(rxPin, txPin);
Adafruit_BME280 bme; // I2C

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE};

// #define DEBUG
#define USE_VOLKSZAEHLER
const char kHostname[] = "192.168.178.34";
const char kPath[] = "/index.php/";
// const char kHostname[] = "###############";
// const char kPath[] = "/middleware.php/data/";

const char *vz_addcmd = ".json?operation=add&value=";

//For UUIDs: Use "" to skip this measurement
const char *vz_uuid_temp = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee1"; //Temperature (°C)
const char *vz_uuid_hum = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee2";  //Absolute humidity (g/m3)
const char *vz_uuid_pres = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee3"; //Absolute atmospheric pressure

const char *vz_uuid_p25 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee4"; //Feinstaub P25
const char *vz_uuid_p10 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeee5"; //Feinstaub P10

#ifdef USE_VOLKSZAEHLER
bool sendVz(const char *uuid, float value)
{
  if (strlen(uuid) == 0)
    return true;

  bool ret = false;
  int err = 0;
  char cValue[16];
  char path[100];

  EthernetClient c;
  HttpClient http(c);

  dtostrf(value, 3, 2, cValue);

  strcpy(path, kPath);
  strcat(path, uuid);
  strcat(path, ".json?operation=add&value=");
  strcat(path, cValue);

#ifdef DEBUG
  Serial.print(F("[vz] HTTP-Request: "));
  Serial.println(path);
#endif

  err = http.get(kHostname, path);
  if (err == 0)
  {
#ifdef DEBUG
    Serial.println(F("startedRequest ok"));
#endif
    err = http.responseStatusCode();
    if (err >= 0 && err == 200)
    {
#ifdef DEBUG
      Serial.println(F("OK"));
#endif
      ret = true;
    }
    else
    {
      Serial.print(F("ERR: "));
      Serial.println(err);
    }
  }
  else
  {
    Serial.print(F("Connect failed: "));
    Serial.println(err);
  }
  http.stop();

  return ret;
}
#endif

void setup()
{
  Serial.begin(115200);
  Serial.println(F("BME280-SDS011->VZ"));

  // Config SDS011
  // sds.begin();
  // sds.setQueryReportingMode();

  // Config BME280
  bme.begin();
  bme.setSampling(Adafruit_BME280::MODE_FORCED,
                  Adafruit_BME280::SAMPLING_X1, // temperature
                  Adafruit_BME280::SAMPLING_X1, // pressure
                  Adafruit_BME280::SAMPLING_X1, // humidity
                  Adafruit_BME280::FILTER_OFF);

#ifdef USE_VOLKSZAEHLER
  while (Ethernet.begin(mac) != 1)
  {
    Serial.println(F("Error DHCP"));
    delay(15000);
  }
  Serial.print(F("local IP address: "));
  Serial.println(Ethernet.localIP());
#endif
}

void loop()
{
  // BME280
  bme.takeForcedMeasurement();
  float temperature = bme.readTemperature();
  float humidity = bme.readHumidity();
  float pressure = bme.readPressure() / 100.0F;

  // SDS011
  // float sdspm25;
  // float sdspm10;
  // sds.wakeup(); // aufwecken
  // delay(30000); //  30 seconds laufen lassen

  // PmResult pm = sds.queryPm(); // Messen
  // if (pm.isOk())
  // {
  //   // Serial.println(pm.toString());
  //   sdspm25 = pm.pm25;
  //   sdspm10 = pm.pm10;
  // }
  // sds.sleep(); // Schlafenlegen

#ifdef DEBUG
  //BME / SDS011
  Serial.print(F("T: "));
  Serial.print((String)temperature);
  Serial.print(F(" *C\nAH: "));
  Serial.print((String)humidity);
  Serial.print(F(" g/m3\nP: "));
  Serial.print((String)pressure);
  Serial.print(F(" hPa\nPM25: "));
  // Serial.print((String)sdspm25);
  // Serial.print(F(" PPM\nPM10: "));
  // Serial.print((String)sdspm10);
  // Serial.println(F(" PPM"));
  Serial.println(F("----------"));

  Serial.flush();
#endif

#ifdef USE_VOLKSZAEHLER
  sendVz(vz_uuid_temp, temperature);
  sendVz(vz_uuid_hum, humidity);
  sendVz(vz_uuid_pres, pressure);
  // sendVz(vz_uuid_p25, sdspm25);
  // sendVz(vz_uuid_p10, sdspm10);
#endif
  delay(10000);
}

Hast du denn mal heraus gefunden, an welcher Stelle der Sketch hängt bzw ein Neustart erfolgt ?

@TO: Was verstehst Du unter Deiner Überschrift? Wenn Du noch mehr rein packst oder wenn er länger läuft?

Hast Du mal alle Char-Arrays auf die richtige Länge (Anzahl Nutzzeichen + '\0') geprüft, ebenso die Schreibzugriffe darauf?

Gruß Tommy

@ HotSystems
Hast du denn mal heraus gefunden, an welcher Stelle der Sketch hängt bzw ein Neustart erfolgt ?

Das ist genau mein Problem, es wird immer wieder die "void setup()" aus geführt oft nicht mal den ersten Serial.println vollständig.

@ Tommy
Was verstehst Du unter Deiner Überschrift? Wenn Du noch mehr rein packst oder wenn er länger läuft?

Wenn ich mehr reinpacke, die d.h die Kommentare an den Zeilen für den zweiten Sensor entferne.

@ Tommy
Hast Du mal alle Char-Arrays auf die richtige Länge (Anzahl Nutzzeichen + '\0') geprüft, ebenso die Schreibzugriffe darauf?

Wie mache ich das am Besten?

Viele Grüße

Händisch zählen, wie sonst?

Du benutzt große Puffer in Funktionen. Die kann der Kompiler bei seiner Speicherberechnung nicht mit berücksichtigen. Also scheint der RAM zu wenig zu werden. Da hilft dann nur ein größerer MC.

Gruß Tommy

Paukel:
Das ist genau mein Problem, es wird immer wieder die "void setup()" aus geführt oft nicht mal den ersten Serial.println vollständig.

Das verstehe ich nicht.
Die Loop wird dann nicht ausgeführt ?

Dann sieht es für mich nach einem Fehler des Sensors BME280 aus.

HotSystems:
Die Loop wird dann nicht ausgeführt ?

Er wird doch ausgeführt -> Ausgabe von "xloop" eingebaut.

...
void loop()
{
  // BME280
  bme.takeForcedMeasurement();
  float temperature = bme.readTemperature();
  float humidity = bme.readHumidity();
  float pressure = bme.readPressure() / 100.0F;

Serial.println(F("xloop"));  // <============

  // SDS011
  float sdspm25;
  float sdspm10;
  sds.wakeup(); // aufwecken
  delay(30000); //  30 seconds laufen lassen

  PmResult pm = sds.queryPm(); // Messen
  if (pm.isOk())
  {
    // Serial.println(pm.toString());
    sdspm25 = pm.pm25;
    sdspm10 = pm.pm10;
  }
  sds.sleep(); // Schlafenlegen
...

Ergibt folgende Ausgabe:
BME280-SDS011->VZ
local IP address: 192.168.178.35
xl BME280-SDS011->VZ
local IP address: 192.168.178.35
xl BME280-SDS011->VZ
... uns so weiter ...
das xl - kommt vom xloop

HotSystems:
Dann sieht es für mich nach einem Fehler des Sensors BME280 aus.

Eigentlich nicht, es sieht genauso aus wenn ich es umdrehe also SDS011 verwende und den BME280 dazu nehmen will.

Dann stimmt diese Aussage nicht.
Das erste println ist schon im Setup vor bme.begin.

Daher meine Vermutung.

Paukel:
Das ist genau mein Problem, es wird immer wieder die "void setup()" aus geführt oft nicht mal den ersten Serial.println vollständig.

Tommy56:
Händisch zählen, wie sonst?

Schade :frowning:
Wenn ich char cValue[8]; bzw. char path[90 ]; optimiere wird es auch nicht besser
vergrößern hilft auch nicht.

Tommy56:
Du benutzt große Puffer in Funktionen. Die kann der Kompiler bei seiner Speicherberechnung nicht mit berücksichtigen. Also scheint der RAM zu wenig zu werden. Da hilft dann nur ein größerer MC.

Ich habe mal versucht das RAM "auszuloten" und die Sensoren entfernt und mit den Buffer gespielt.

#include <SPI.h>
#include <HttpClient.h>
#include <Ethernet.h>
#include <EthernetClient.h>

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE};

const char kHostname[] = "192.168.178.34";
const char kPath[] = "/index.php/";

const char *vz_addcmd = ".json?operation=add&value=";

const char *vz_uuid_temp = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee1"; //Temperature (°C)
const char *vz_uuid_hum = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee2";  //Absolute humidity (g/m3)
const char *vz_uuid_pres = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee3"; //Absolute atmospheric pressure

const char *vz_uuid_p25 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee4"; //Feinstaub P25
const char *vz_uuid_p10 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee5"; //Feinstaub P10

bool sendVz(const char *uuid, float value)
{
  if (strlen(uuid) == 0)
    return true;

  bool ret = false;
  int err = 0;
  char cValue[16];
  char path[500];

  EthernetClient c;
  HttpClient http(c);
  dtostrf(value, 3, 2, cValue);
  strcpy(path, kPath);
  strcat(path, uuid);
  strcat(path, ".json?operation=add&value=");
  strcat(path, cValue);

  err = http.get(kHostname, path);
  if (err == 0)
  {

    err = http.responseStatusCode();
    if (err >= 0 && err == 200)
    {
      Serial.println(F("OK"));
      ret = true;
    }
    else
    {
      Serial.print(F("ERR: "));
      Serial.println(err);
    }
  }
  else
  {
    Serial.print(F("Connect failed: "));
    Serial.println(err);
  }
  http.stop();

  return ret;
}

void setup()
{
  Serial.begin(115200);
  Serial.println(F("RAM test"));

  while (Ethernet.begin(mac) != 1)
  {
    Serial.println(F("Error DHCP"));
    delay(15000);
  }
  Serial.print(F("local IP address: "));
  Serial.println(Ethernet.localIP());
  delay(1000);
}

void loop()
{

  float temperature = 23.61;
  float humidity = 50.11;
  float pressure = 993.57;

  float sdspm25 = 41.80;
  float sdspm10 = 42.20;

  Serial.println(F("loop"));
  Serial.flush();

  sendVz(vz_uuid_temp, temperature);
  sendVz(vz_uuid_hum, humidity);
  sendVz(vz_uuid_pres, pressure);
  sendVz(vz_uuid_p25, sdspm25);
  sendVz(vz_uuid_p10, sdspm10);

  delay(10000);
}

Dabei habe ich char path[500]; deutlich erhöht. -> kein Problem.
Bei char path[1000]; -> zusätzliche komische Zeichen in der seriellen Ausgabe => Aber der HTTP-Request ist okay.

KEINE Neustarts bzw. mehrfaches ausführen der void setup().

Man kann halt schlecht sagen was die Lib's an RAM benötigen ...

Vielleicht portiere ich es auf einen ES8266 ...

Gruß Paul

Hast Du mal die Idee von hotsystems verfolgt? Also mal alle Sensoren ohne den Volkszähler gecheckt?

Gruß Tommy

Tommy56:
Hast Du mal die Idee von hotsystems verfolgt? Also mal alle Sensoren ohne den Volkszähler gecheckt?

Ja klar, auslesen der beiden Sensoren und seriell ausgeben tut.

Gruß Paul

Zur weiteren und besseren Fehlersuche solltest du deine einzelnen Sensoren in einzelne Funktionen packen. Dann kann man diese leichter ein und ausschalten.

Und evtl. auch besser erweitern.

Meinen Arduino Nano soll Messwerte von 2 Sensoren abholen und per Http-Request an einen Server schicken.
Das Auslesen der Sensoren alleine funktioniert, das Senden der Daten von einem Sensor (egal Welcher) ebenfalls.
NUR alles zusammen funktioniert nicht.

Das Programm startet immer wieder neu, mit verstümmelter serieller Ausgabe.

Auf einem Arduino Mega 2560 funktioniert das Programm (2 Sensoren + Senden) allerdings.

Das deutet darauf hin, daß am ATmega328 auf dem NANO zuwenig RAM hat um den Bedarf zu stillen.

Grüße Uwe

Danke an alle für die Unterstützung.

Ich bin jetzt mit dem Mega-Board in den provisorischen Testbetrieb ("fliegende" Verkabelung) gegangen.
Das läuft jetzt über 10 Stunden. :slight_smile:

Gruß Paul

Ein größerer Prozessor ist sicherlich der sichere Weg, da auch die Bibliotheken schon einiges an RAM brauchen. Aber da lässt auch so noch etwas RAM sparen. Das F() Makro ist nicht alles:

Auch für die normalen C String Funktionen gibt es PROGMEM Varianten. So wird das:

strcat(path, ".json?operation=add&value=");

Zu:

strcat_P(path, PSTR(".json?operation=add&value="));

Und braucht man wirklich 500 Bytes für den Puffer? Das ist das Hauptproblem. Auf einem Atmega328 ist das ein Viertel des Speichers. Es sieht nicht so aus als ob der Pfad so extrem lang ist

Serenifly:
Und braucht man wirklich 500 Bytes für den Puffer?

Ich bin Anfänger was C und Arduino angeht. Wie kommst Du auf die 500 Bytes?
Ist nicht ein Char = 1 Byte?

Für die Variablen cValue[8] und path[90] würden reichen.

Gruß Paul

Paukel:
Ist nicht ein Char = 1 Byte?

Ja.

Paukel:
Wie kommst Du auf die 500 Bytes?

char path[500];

Das ist ein Feld von 500 Zeichen.

Mal eine grundlegende Frage. Müssen die Dinger so lang sein? Weil deren Inhalt unterscheidet sich ja nur in der letzten Ziffer. Da könnte die doch reichen?

const char *vz_uuid_temp = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee1"; //Temperature (°C)
const char *vz_uuid_hum = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee2";  //Absolute humidity (g/m3)
const char *vz_uuid_pres = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee3"; //Absolute atmospheric pressure

const char *vz_uuid_p25 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee4"; //Feinstaub P25
const char *vz_uuid_p10 = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeee5"; //Feinstaub P10

Die gehen ja auch in die path-Größe mit ein.

Gruß Tommy