Communication with COM-Terminal "CoolTerm" stops after long usage (24h and more)

Hello!

I am using the program below to monitor a gascounter (MilliGascounter; http://www.milligascounter.de/).
Basically, the the program counts signals from the gasmeter and does some arithmetics with it. After a certain time (standard is 4h) the results are sent to a PC.
There, a very useful program called "CooltTerm" receives the data and saves it into a *.txt-file to process it in Excel later.

Everything was working just fine, until I recently did some changes. Now CoolTerm works as expected for a day or sometimes even a week (the experiments take quite a lot of time...), then suddenly CoolTerm doesn't receive any more data. However, the board seems to continue working, as the counter is still going up (when I restart, the saved value is higher than the last one documented. Also the results fit the expectations, so I don't think, they are just randomly created or anything).
Sadly I can't say what exactly caused the problems. I mainly changed the time recording from simple hours based on the millis()-funktion to an actual time using the time-library. Also the possibility to change the interval-length and to print manually are new.

I really hope, you can help me...

Thank you in advance.

PS: All the comments are in German, as it is my mother language. If you need any explanations, feel free to ask.

#include <Time.h>
#include <EEPROM.h>

const int gaszaehlerIn = 2;    // digitalPin des Gaszählers
const float volume = 3.57;    // Volumen pro Ausschlag; empirisch ermittelt
float interval = 240;    // Intervalllänge (in min)
float flowRate = 0;

int currentState = 0;    // aktueller Status des Reed-Schalters (offen / geschlossen)
int lastState = 0;    // vorheriger Status

long signalCounter = 0;    // Anzahl an Ausschlägen
long lastSignalCounter = 0;    // Ausschläge bis zur jeweils letzten seriellen Ausgabe der Daten

unsigned long startTime = 0;    // Startzeit des Loops; ermöglicht die Regelung seiner Dauer
unsigned long printDif = 0;    // Zeit zwischen der letzten und aktuellen Ergebniszeile; zur korrekten Bestimmung des Volumenstroms

int Tag = 0;
int Monat = 0;
int Jahr = 0;
int Stunde = 0;
int Minute = 0;
const int Sekunde = 0;

String command = "";

void setup() {
  pinMode(gaszaehlerIn, INPUT_PULLUP);  // eingehende Signale werden registriert

  Serial.begin(9600);  // Baud für Verbindung wird festgelegt
  while (!Serial) {  // Board wartet auf eine serielle Verbindung
    ;
  }
  printDif = now();
  
  Serial.println("Aktuelle Zeit einstellen [Tag,Monat,Jahr,Stunden,Minuten]");
  while (!Serial.available());
  getTime();

  setTime(Stunde, Minute, Sekunde, Tag, Monat, Jahr);
  Serial.println("Zeit eingestellt");
  Serial.println("");
  
  printHeader();

  signalCounter = EEPROMReadlong(0);    // signalCounter vom letzten Mal wird geladen

  lastSignalCounter = signalCounter;
  
  delay(1000);    // muss mindestens eine Sekunde sein, da für den Volumenstrom sonst durch 0 geteilt wird
  printResults();
}

void loop() {
  startTime = now();    // now() gibt die Zahl an Sekunden, die seit 1970 verstrichen sind
  
  do {
    currentState = digitalRead(gaszaehlerIn);
    if (currentState != lastState) {  // eine Änderung des Signals vom Gaszähler initiiert den nächsten Schritt
      if (currentState == LOW) {    // ist das Signal LOW? (=liegt eine Spannung an?)
        signalCounter++;   // ist dem so, wird der Counter um 1 erhöht
        delay (250);   // 250ms Wartezeit, damit ein Signal nicht als mehrere gezählt wird
      }
      else {   // für den Fall, dass das Signal LOW ist:
        ;
      }
    }
    lastState = currentState;  // lastState und currentState werden wieder gleich gesetzt

    while (Serial.available()) {
      command = Serial.readString();
      if (command == "clear") {    // Vorgehen, falls "clear" gesendet wurde
        Serial.println("");
        for (int i = 0; i <= 3; i++) {    //
          EEPROM.write(i, 0);             // signalCounter wird wieder auf 0 gesetzt
          Serial.print(".");
          delay(250);
        }
        Serial.println("");
        Serial.println("Variablen zurueckgesetzt, Programm gestoppt.");
        while (1) {}
      }
      if (command == "interval") {    // Vorgehen, falls "Intervall" gesendet wurde
        Serial.println("");
        Serial.println("Bitte Intervalldauer in Minuten eingeben");
        while(!Serial.available());
        interval = Serial.parseFloat();
        Serial.println("Intervalldauer angepasst");
        Serial.println("");
      }
      if (command == "print") {
        printResults();
        
        lastSignalCounter = signalCounter;
        
        long address = 0;
        EEPROMWritelong(address, signalCounter);
        address += 4;
      }
      if (command == "help") {
        Serial.println("");
        Serial.println("- 'interval' ermoeglicht ein manuelles Festlegen des Abstands zwischen zwei Ergebniszeilen.");
        Serial.println("- 'print' gibt eine neue Ergebniszeile aus, waehrend die Intervalldauer unveraendert bleibt.");
        Serial.println("- 'clear' loescht den gespeicherten Stand des Gaszaehlers und stoppt das Programm.");
        Serial.println("");
      }
    }
  } while (((now() - startTime)) < (interval * 60));    // Dauer des Loops

  printResults();

  long address = 0;
  EEPROMWritelong(address, signalCounter);
  address += 4;

  lastSignalCounter = signalCounter;
}

void EEPROMWritelong(int address, long value)    // die Funktion EEPROMWritelong() wird etabliert
{ //
  byte four = (value & 0xFF);                    //dabei wird eine 4 Byte große long-Variable
  byte three = ((value >> 8) & 0xFF);            //in ihre einzelnen Bytes zerlegt (one ... four),
  byte two = ((value >> 16) & 0xFF);             //die dann auf separate Speicherplätze gelegt
  byte one = ((value >> 24) & 0xFF);             //werden.
  //
  EEPROM.write(address, four);                   //
  EEPROM.write(address + 1, three);              //
  EEPROM.write(address + 2, two);                //
  EEPROM.write(address + 3, one);                //
}

long EEPROMReadlong(long address)                // Funktion EEPROMReadlong wird etabliert
{ //
  long four = EEPROM.read(address);              // zunächst werden die vier Bytes ausgelesen
  long three = EEPROM.read(address + 1);         //
  long two = EEPROM.read(address + 2);           //
  long one = EEPROM.read(address + 3);           //

  // die Funktion gibt die wieder zusammengesetzte Variable aus:
  return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
}

void printHeader() {
  Serial.print("Zeit");                             //
  Serial.print(";");                                //
  Serial.print("Volumen gesamt [ml]");              //
  Serial.print(";");                                //
  Serial.print("aktueller Volumenstrom [ml/min]");  //
  Serial.print(";");                                //
  Serial.println("Ausschlaege");                    // Benennung der Tabellenspalten
}

void printResults() {
  flowRate = ((signalCounter - lastSignalCounter) * volume) / (now() - printDif) * 60;
  
  Serial.print(day());
  Serial.print(".");
  Serial.print(month());
  Serial.print(".");
  Serial.print(year());
  Serial.print(" ");
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  Serial.print(":");
  Serial.print(second());
  Serial.print(";");
  Serial.print(signalCounter * volume);  // Berechnung des Gesamtvolumens
  Serial.print(";");
  Serial.print(flowRate);  // Berechnung des aktuellen Volumenstroms
  Serial.print(";");
  Serial.println(signalCounter);  // Menge der Ausschläge wird eingetragen
  
  printDif = now();  // Zur Bestimmung des zeitlichen Abstands zwischen zwei Messungen
}

void getTime() {
  String timeSet = "";
  String arg = "";

  int beginIdx = 0;
  int idx = 0;

  while (Serial.available()) {
    timeSet = Serial.readString();
  }
  
  idx = timeSet.indexOf(',');
  
  arg = timeSet.substring(beginIdx, idx);
  Tag = arg.toInt();
  beginIdx = idx + 1;
  idx = timeSet.indexOf(",", beginIdx);
  
  arg = timeSet.substring(beginIdx, idx);
  Monat = arg.toInt();
  beginIdx = idx + 1;
  idx = timeSet.indexOf(",", beginIdx);
  
  arg = timeSet.substring(beginIdx, idx);
  Jahr = arg.toInt();
  beginIdx = idx + 1;
  idx = timeSet.indexOf(",", beginIdx);
  
  arg = timeSet.substring(beginIdx, idx);
  Stunde = arg.toInt();
  beginIdx = idx + 1;
  idx = timeSet.indexOf(",", beginIdx);
  
  arg = timeSet.substring(beginIdx, idx);
  Minute = arg.toInt();
  beginIdx = idx + 1;
  idx = timeSet.indexOf(",", beginIdx);
}

japhwil:
when I restart,

What are you restarting ?

Just CoolTerm?
Or the Arduino?
or both ?

the saved value is higher

What value is higher ?

Can you add some code to your Arduino that will blink the on-board LED so that, if the Arduino crashes you will know because it stops flashing ?

...R

I meant restarting the Arduino.
As you can see, every time the results are printed via Serial, the counter is stored in the EEPROM. When the board is restarted, it loads the counter from the EEPROM. Since the counter is higher when I restart the board, I assume it was still working, while the PC didn't receive anything.

Regards

japhwil:
Since the counter is higher when I restart the board, I assume it was still working, while the PC didn't receive anything.

I think it is more likely that the Arduino stopped sending but, perhaps, it saved one extra value to the SD Card after the last value it sent to the PC. Have you any way of knowing what values it should have sent? Maybe you could add some code so the Arduino sends a count value (and saves it to the SD Card also).

If you really think the problem is with CoolTerm try using puTTY and see what happens.

...R

Hey guys,

I'am having the same problem. I'am doing experiments with batteries in a refrigerator.
The Arduino Uno is outside of the refrigerator. Only the batteries and a temperature sensor are inside of it.
The data is logged every 10 seconds. It works very well until, suddenly, CoolTerm stops to receive data.

Anyone has a clue of what could be happening?

I appreciate any answer.
See you!

leomr85:
Anyone has a clue of what could be happening?

Did you try PuTTY like I suggested in Reply #3 ?

Have you some means to know if the Arduino crashes - perhaps add some code so the onboard LED should flash at regular intervals.

Are you saving the data to an SD Card? Are you saving a count value so you can tell is data is missing?

...R

The String library doesn't work well when you have a small amount of ram available and mysterious crashes after the program has been working for hours or days are symptomatic of the problem.
You need to replace all uses of String with null-terminated C strings. If you are used to using things like timeSet.substring, there's a learning curve involved in converting this all to C strings, but it will get rid of once source of mysterious crashes.

Pete