Uncommanded loop second time through

Hello,
I am trying to read several DHT sensors and update them to a server that is online. The first time through the loop it runs fine. Makes the GET call as required and posts the information. It waits the specified amount of time and starts a second loop, this time though it goes through the DHT loop twice until, I think, it overuns the char spacing I allot for the statement and then forces a restart of the Arduino. Upon restart, it will do one good call, then repeat.

#include "DHT.h"
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <MemoryFree.h>


//  REAL TIME CLOCK DS 1307

RTC_DS1307 rtc;


// Local Network Settings
byte mac[] = {0xab, 0xb3, 0xef, 0x2F, 0x1a, 0x2d}; // Must be unique on local network

// Emoncms Settings
char EmoncmsAddress[] = "emoncms.org";
char writeAPIKey[] = "&apikey=xxxx4fbaaa359xxxxdb0xxxx1dxxxxaa";
char writeNode1[] = "node=1&csv=";
char writeNode2[] = "node=2&csv=";
char Emoncmsbegin[] = "/input/post.json?";
char transmission1[375];
//char transmission2[240];


const long updateEmoncmsInterval = 20 * 1000;      // Time interval in milliseconds to update ThingSpeak (number of seconds * 1000 = interval)

// Variable Setup
long lastConnectionTime = 0; 
boolean lastConnected = false;
int failedCounter = 0;

// Initialize Arduino Ethernet Client
EthernetClient client;


//DHT Settings

#define DHTTYPE DHT21

DHT dht01(23, DHTTYPE);DHT dht02(22, DHTTYPE);DHT dht03(31, DHTTYPE);DHT dht04(30, DHTTYPE);
DHT dht05(25, DHTTYPE);DHT dht06(24, DHTTYPE);DHT dht07(29, DHTTYPE);DHT dht08(28, DHTTYPE);
DHT dht09(27, DHTTYPE);DHT dht10(26, DHTTYPE);DHT dht11(36, DHTTYPE);DHT dht12(37, DHTTYPE);
DHT dht13(34, DHTTYPE);DHT dht14(35, DHTTYPE);DHT dht15(38, DHTTYPE);DHT dht16(39, DHTTYPE);
DHT dht17(32, DHTTYPE);DHT dht18(33, DHTTYPE);DHT dht19(40, DHTTYPE);DHT dht20(41, DHTTYPE);

DHT* dhtList[] = {&dht01, &dht02, &dht03, &dht04, &dht05, &dht06, &dht07, &dht08,
&dht09, &dht10, &dht11, &dht12, &dht13, &dht14, &dht15, &dht16, &dht17, &dht18, &dht19, &dht20};


#define NUM_DHTS (sizeof(dhtList)/sizeof(DHT*))
typedef char humStr[7];  //4 digits + decimal point + 1 decimal + null terminator
typedef char tempStr[7]; //4 digits + decimal point + 1 decimal + null terminator



humStr numhum[NUM_DHTS];
tempStr numtemp[NUM_DHTS];
char exttemp[7];
char exthum[7];

////////////////////////////////////////////////////////////////////////////
//
//                     SETUP
//
void setup()
{
  // Start Serial for debugging on the Serial Monitor
  Serial.begin(9600);
  pinMode(SS, OUTPUT);
  
  // Start Ethernet on Arduino
  startEthernet();
  delay(1000);
  
  //  Start DHT22
  dht01.begin();   dht02.begin();   dht03.begin();   dht04.begin();
  dht05.begin();   dht06.begin();   dht07.begin();   dht08.begin();
  dht09.begin();   dht10.begin();   dht11.begin();   dht12.begin();
  dht13.begin();   dht14.begin();   dht15.begin();   dht16.begin();
  dht17.begin();   dht18.begin();   dht19.begin();   dht20.begin();
 }

/////////////////////////////////////////////////////////////////////////
//
//                         LOOP
//
void loop()
{
  long currentTime = millis();
  
  if (currentTime - lastConnectionTime > updateEmoncmsInterval)
  {
     //memset(transmission1, '\0', 350);
     strcat(transmission1,Emoncmsbegin);
     strcat(transmission1,writeNode1);
     Serial.print(freeMemory());
     
     
     for (int i = 0; i < NUM_DHTS; i++)
     {
      // Read value from DHT Sensor
      float h = dhtList[i]->readHumidity();
      float t = dhtList[i]->readTemperature();
      if (isnan(h)) 
      {
        h = 0.0;
        t = 0.0;
        dtostrf(h, 3, 1, numhum[i]);
        dtostrf(t, 3, 1, numtemp[i]);
      }
      else
      {
      
      dtostrf(h, 4, 1, numhum[i]);
      dtostrf(t, 4, 1, numtemp[i]);
          }
      strcat(transmission1,numtemp[i]);
      strcat(transmission1, ",");
      strcat(transmission1, numhum[i]);
      if (i < NUM_DHTS-1) strcat(transmission1, ",");
      
      
      Serial.print(i); Serial.print("     ");
      Serial.print((char*)numhum[i]); Serial.print("     ");
      Serial.println((char*)numtemp[i]);
       }
     strcat(transmission1, writeAPIKey);
     //Serial.println(transmission1);
     //strcat(transmission2, writeAPIKey);
  }
  // Disconnect from Emoncms
  if (!client.connected() && lastConnected)
  {
    Serial.println("...disconnected");
    Serial.println();
    
    client.stop();
  }
  
  // Update Emoncms
  if(!client.connected() && (currentTime - lastConnectionTime > updateEmoncmsInterval))
  {
    Serial.println(transmission1);
    //Serial.println(transmission2);
    
    updateEmoncms(transmission1);
        
    Serial.println(F("Sent Transmission"));
    memset(transmission1, '\0', 300);
  }
    
      // Check if Arduino Ethernet needs to be restarted
  if (failedCounter > 3 ) {startEthernet();}
  
  lastConnected = client.connected();
  
  
}

/////////////////////////////////////////////////////////////////////////////
//
//                 UPDATE Emoncms
//
void updateEmoncms(String tsData)
{
  if (client.connect(EmoncmsAddress, 80))
  {         
    client.print("GET ");
    client.print(tsData);
    client.println(" HTTP/1.0");
    client.println("Host: emoncms.org");
    client.print("User-Agent: Arduino-ethernet");
    client.println("Connection: close");
    client.println();
    //client.stop();
    lastConnectionTime = millis();
    
    if (client.connected())
    {
      Serial.println("Connecting to Emoncms...");
      Serial.println();
      
      failedCounter = 0;
    }
    else
    {
      failedCounter++;
  
      Serial.println("Connection to Emoncms failed ("+String(failedCounter, DEC)+")");   
      Serial.println();
    }
    
  }
  else
  {
    failedCounter++;
    
    Serial.println("Connection to Emoncms Failed ("+String(failedCounter, DEC)+")");   
    Serial.println();
    
    lastConnectionTime = millis(); 
  }
}

/////////////////////////////////////////////////////////////////////////
//
//                       START ETHERNET
//
void startEthernet()
{
  
  client.stop();
 
  Serial.println("Connecting Arduino to network...");
  Serial.println();  

  delay(1000);
  
  // Connect to network amd obtain an IP address using DHCP
  if (Ethernet.begin(mac) == 0)
  {
    Serial.println("DHCP Failed, reset Arduino to try again");
    Serial.println();
  }
  else
  {
    Serial.println("Arduino connected to network using DHCP");
    Serial.println();
  }
  
  delay(1000);
}

Here is the text from the serial monitor:

...disconnected

Connecting Arduino to network...

Connecting Arduino to network...

Arduino connected to network using DHCP

49380     17.7     23.9
1     17.8     23.7
2     18.2     23.6
3     18.0     23.7
4     18.4     23.6
Read fail5     0.0     0.0
6     18.0     24.0
7     18.7     23.4
8     20.9     22.8
9     20.8     22.8
10     18.2     22.9
11     19.6     23.0
12     21.3     22.2
13     22.3     22.4
14     21.1     22.3
15     18.9     22.4
Read fail16     0.0     0.0
Read fail17     0.0     0.0
Read fail18     0.0     0.0
Read fail19     0.0     0.0
/input/post.json?node=1&csv=23.9,17.7,23.7,17.8,23.6,18.2,23.7,18.0,23.6,18.4,0.0,0.0,24.0,18.0,23.4,18.7,22.8,20.9,22.8,20.8,22.9,18.2,23.0,19.6,22.2,21.3,22.4,22.3,22.3,21.1,22.4,18.9,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0&apikey=xx114faa0xx5xxxx753db0x9dxxdexxxxx8
Connecting to Emoncms...

Sent Transmission
49380     17.7     24.1
1     17.7     23.8
2     18.2     23.6
3     18.0     23.8
4     18.4     23.7
Read fail5     0.0     0.0
6     18.0     24.1
7     18.7     23.3
8     21.0     22.9
9     20.8     22.9
10     18.1     23.0
11     19.6     23.1
12     21.3     22.2
13     22.3     22.4
14     21.1     22.4
15     19.0     22.4
Read fail16     0.0     0.0
Read fail17     0.0     0.0
Read fail18     0.0     0.0
Read fail19     0.0     0.0
49380     17.4     24.1
1     17.7     23.9
2     18.1     23.6
3     18.0     23.9
4     18.2     23.7
Read fail5     0.0     0.0
6     17.8     24.1
7     18.6     23.4
8     20.9     23.0
9     20.8     22.9
10     18.1     23.1
11     19.6     23.0
12     21.2     22.3
13     22.2     22.4
14     21.1     22.4
15     19.0     22.5
Read fail16     0.0     0.0
Read fail17     0.0     0.0
Read fail18     0.0     0.0
Read fail19     0.0     0.0
...disconnected

Connecting Arduino to network...

Connecting Arduino to network...

Arduino connected to network using DHCP

Anyway, thanks for looking. Let me know if I need to clarify anything.

Tim

What are you running this on? How many bytes does a DHT object take?

I don't have the hardware so I'm just wondering is all.

You could ditch the link list if you declare the DHT objects as an empty array and set them with the begins, the array index takes place of the linked list kept in RAM.

At some point the stack runs a bit deep and crosses into the heap, which might lead to the stack getting over written but either way it's not good. With all those libraries, every function call loads the stack with return and passed args. That doesn't get freed up if that function calls another, and return and args for that get stacked. How many layers, how many passed args? Don't use functions to make your code look clean without declaring them inline to save stacking a return address. How much of that do you see in libraries and examples?

OTOH you may be running on a MEGA with 8K RAM or something bigger, IIRC Frankenduino Galileo has 256MB.

Thanks. This is going on a Arduino Mega, the 4938 number you see at the beginning of the DHT read section is the report from the "MemoryFree" library. So I shouldn't be running out of RAM. My thought is a string somewhere (I am betting its the String tsData going into the update funciton) is overwriting something that causes the Mega to go nuts and then restart.

Tim

You've got some pretty substantial global variables there and could easily be running out of memory, which would lead to memory corruption resulting in the restarts. However, there is also some code appending to transmission1 which is not very robust and might result in you overflowing that, leading to similar symptoms.

I suggest you add code to show the free memory when the sketch starts - there is sample code for that in the playground. Alternatively, recent versions of the IDE report that for you during compilation.

Also use strncat() instead of strcat() to ensure that you don't overflow the buffer. Have you measured how many characters are actually being stored in transmission1? I haven't, but presumably you could find it easily just by doing a character count of the data that was output.

Finally, you're using the problematic String class in several places. Get rid of it.

You still should make an array of the DHT objects and access them by index in loops, not edited copy&paste code sections.

I have added the "freeRam" function from Adafruit into the sketch and have it reporting periodically through the sketch to the serial monitor. I have also changed:

/  dht01.begin();   dht02.begin();   dht03.begin();   dht04.begin();
//  dht05.begin();   dht06.begin();   dht07.begin();   dht08.begin();
//  dht09.begin();   dht10.begin();   dht11.begin();   dht12.begin();
//  dht13.begin();   dht14.begin();   dht15.begin();   dht16.begin();
//  dht17.begin();   dht18.begin();   dht19.begin();   dht20.begin();

to this:

for (int i=0; i < NUM_DHTS; i ++)
  {
    dhtList[i]->begin();
  }

Which makes for much nicer code. I have also gone back through and any constant string has been F() blocked. I have also changed some of my global variables and have sent them to live only in the functions for which they are required.

I will be near the Mega later this afternoon and will report back. Thanks for the suggestions.

All right, here is my further modified code:

#include "DHT.h"
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include "RTClib.h"
#include <SD.h>
#include <MemoryFree.h>


//  REAL TIME CLOCK DS 1307

RTC_DS1307 rtc;


// Local Network Settings
byte mac[] = {0xAA, 0xAA, 0xXX, 0x0F, 0xXX, 0x2C}; // Must be unique on local network

// Emoncms Settings
char writeNode[12] = "node=1&csv=";
char transmission1[325];



const long updateEmoncmsInterval = 20;      // Time interval in seconds to update Emoncms (number of seconds = interval)

// Variable Setup
DateTime lastConnectionTime = 0;
DateTime currentTime;
boolean lastConnected = false;
int failedCounter = 0;

// Initialize Arduino Ethernet Client
EthernetClient client;


//DHT Settings

#define DHTTYPE DHT21

DHT dht01(23, DHTTYPE);DHT dht02(22, DHTTYPE);DHT dht03(31, DHTTYPE);DHT dht04(30, DHTTYPE);
DHT dht05(25, DHTTYPE);DHT dht06(24, DHTTYPE);DHT dht07(29, DHTTYPE);DHT dht08(28, DHTTYPE);
DHT dht09(27, DHTTYPE);DHT dht10(26, DHTTYPE);DHT dht11(36, DHTTYPE);DHT dht12(37, DHTTYPE);
DHT dht13(34, DHTTYPE);DHT dht14(35, DHTTYPE);DHT dht15(38, DHTTYPE);DHT dht16(39, DHTTYPE);
DHT dht17(32, DHTTYPE);DHT dht18(33, DHTTYPE);DHT dht19(40, DHTTYPE);DHT dht20(41, DHTTYPE);

DHT* dhtList[] = {&dht01, &dht02, &dht03, &dht04, &dht05, &dht06, &dht07, &dht08,
&dht09, &dht10, &dht11, &dht12, &dht13, &dht14, &dht15, &dht16, &dht17, &dht18, &dht19, &dht20};

#define NUM_DHTS (sizeof(dhtList)/sizeof(DHT*))
typedef char humStr[7];  //4 digits + decimal point + 1 decimal + null terminator
typedef char tempStr[7]; //4 digits + decimal point + 1 decimal + null terminator

humStr numhum[NUM_DHTS];
tempStr numtemp[NUM_DHTS];
char exttemp[7];
char exthum[7];

void setup()
{
  // Start Serial for debugging on the Serial Monitor
  Serial.begin(9600);
  pinMode(SS, OUTPUT);
  Wire.begin();
  rtc.begin();
  
  // Start Ethernet on Arduino
  startEthernet();
  delay(1000);
  
  //  Start DHT22
  for (int i=0; i < NUM_DHTS; i ++)
  {
    dhtList[i]->begin();
  }

 
  Serial.print(F("After Setup freeRam ="));
  Serial.println(freeRam());
 
 }


void loop()
{
  currentTime = rtc.now();
  Serial.print(F("freeRam ="));
  Serial.println(freeRam());
  Serial.print(F("lastupdate:"));
  Serial.println(currentTime.unixtime() - lastConnectionTime.unixtime());
  
  serialprinttime();
  
  if (currentTime.unixtime() - lastConnectionTime.unixtime() > updateEmoncmsInterval)
  {
              
     for (int i = 0; i < NUM_DHTS; i++)
     {
      // Read value from DHT Sensor
      float h = dhtList[i]->readHumidity();
      float t = dhtList[i]->readTemperature();
      if (isnan(h)) 
      {
        h = 0.0;
        t = 0.0;
        dtostrf(h, 3, 1, numhum[i]);
        dtostrf(t, 3, 1, numhum[i]);
      }
      else{
      
      dtostrf(h, 4, 1, numhum[i]);
      dtostrf(t, 4, 1, numtemp[i]);
          }
      strcat(transmission1,numtemp[i]);
      strcat(transmission1, ",");
      strcat(transmission1, numhum[i]);
      if (i < NUM_DHTS-1) strcat(transmission1, ",");
      
      
      Serial.print(i); Serial.print("     ");
      Serial.print((char*)numhum[i]); Serial.print("     ");
      Serial.println((char*)numtemp[i]);
       }
     
     Serial.print(F("At the end of DHT read freeRam ="));
     Serial.println(freeRam());
  }
  // Disconnect from Emoncms
  if (!client.connected() && lastConnected)
  {
    Serial.println(F("...disconnected"));
    Serial.println();
    
    client.stop();
  }
  
  // Update Emoncms
  if(!client.connected())
  {
    Serial.println(transmission1);
        
    updateEmoncms(transmission1, writeNode);
    delay(100);
    
   Serial.println(F("Sent Transmission"));
    memset(transmission1, '\0', 325);
    
        // Check if Arduino Ethernet needs to be restarted
  if (failedCounter > 3 ) {startEthernet();}
  
  lastConnected = client.connected();
  }

}


void updateEmoncms(char emData[325] , char writeNode[])
{
  if (client.connect("emoncms.org", 80))
  {         
    client.print(F("GET "));
    client.print(F("/input/post.json?"));
    client.print(writeNode);
    client.print(emData);
    client.print(F("&apikey=XXXXXXXXXXXXXXXXXXXXXXXXXXXX"));
    client.println(F(" HTTP/1.1"));
    client.println(F("Host: emoncms.org"));
    client.print(F("User-Agent: Arduino-ethernet"));
    client.println(F("Connection: close"));
    client.println();
    
    lastConnectionTime = rtc.now();
    Serial.print(F("After Emoncms transmission freeRam ="));
    Serial.println(freeRam());
    memset(emData, '\0', 325);
    
    if (client.connected())
    {
      Serial.println(F("Connecting to Emoncms..."));
      Serial.println();
      
      failedCounter = 0;
    }
    else
    {
      failedCounter++;
  
      Serial.println("Connection to Emoncms failed ("+String(failedCounter, DEC)+")");   
      Serial.println();
    }
    
  }
  else
  {
    failedCounter++;
    
    Serial.println("Connection to Emoncms Failed ("+String(failedCounter, DEC)+")");   
    Serial.println();
    
    lastConnectionTime = millis(); 
  }
}

/////////////////////////////////////////////////////////////////////////
//
//                       START ETHERNET
//
void startEthernet()
{
  
  client.stop();
 
  Serial.println(F("Connecting Arduino to network..."));
  Serial.println();  

  delay(1000);
  
  // Connect to network amd obtain an IP address using DHCP
  if (Ethernet.begin(mac) == 0)
  {
    Serial.println(F("DHCP Failed, reset Arduino to try again"));
    Serial.println();
  }
  else
  {
    Serial.println(F("Arduino connected to network using DHCP"));
    Serial.println();
  }
  
  delay(1000);
}

int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

And here is my new Serial Monitor:

freeRam =5281
lastupdate:1393937709
2014/3/4 16:54:54
0     24.1     23.4
1     23.9     23.4
2     24.1     23.5
3     24.0     23.6
4     24.3     23.5
Read fail5     0.0     
6     24.0     23.7
7     24.4     23.2
8     26.3     23.0
9     26.2     23.1
10     23.7     23.1
11     25.3     23.2
12     26.5     22.6
13     27.3     22.8
14     26.2     22.8
15     24.3     22.9
Read fail16     0.0     
Read fail17     0.0     
Read fail18     0.0     
Read fail19     0.0     
At the end of DHT read freeRam =5281
23.4,24.1,23.4,23.9,23.5,24.1,23.6,24.0,23.5,24.3,,0.0,23.7,24.0,23.2,24.4,23.0,26.3,23.1,26.2,23.1,23.7,23.2,25.3,22.6,26.5,22.8,27.3,22.8,26.2,22.9,24.3,,0.0,,0.0,,0.0,,0.0
After Emoncms transmission freeRam =5230
Connecting to Emoncms...

Sent Transmission
freeRam =5281
lastupdate:5
2014/3/4 16:55:10
freeRam =5281
lastupdate:23
2014/3/4 16:55:28
0     24.1     23.4
1     24.0     23.5
2     24.1     23.5
3     24.1     23.6
4     24.3     23.5
Read fail5     0.0     
6     24.0     23.7
7     24.5     23.3
8     26.4     23.1
9     26.2     23.0
10     23.8     23.1
11     25.4     23.3
12     26.5     22.6
13     27.4     22.8
14     26.2     22.8
15     24.2     22.8
Read fail16     0.0     
Read fail17     0.0     
Read fail18     0.0     
Read fail19     0.0     
At the end of DHT read freeRam =5281
freeRam =5281
lastupdate:37
2014/3/4 16:55:42
0     24.1     23.4
1     24.1     23.5
2     24.1     23.5
3     24.1     23.6
4     24.3     23.5
Read fail5     0.0     
6     24.1     23.8
7     24.5     23.2
8     26.4     23.0
9     26.2     23.0
10     23.7     23.1
11     25.3     23.2
12     26.5     22.6
13     27.3     22.8
14     26.2     22.7
15     24.3     22.9
Read fail16     0.0     
Read fail17     0.0     
Read fail18     0.0     
Read fail19  ðConnecting Arduino to network...

Arduino connected to network using DHCP

After Setup freeRam =5301
freeRam =5281
lastupdate:1393952157
2014/3/4 16:55:57
0     24.1     23.4
1     24.1     23.5
2     24.0     23.5
3     24.0     23.6
4     24.4     23.5
Read fail5     0.0     
6     24.0     23.7
7     24.5     23.3
8     26.4     23.0
9     26.2     23.0
10     23.7     23.1
11     25.4     23.3
12     26.5     22.7
13     27.3     22.8
14     26.1     22.8
15     24.1     22.8
Read fail16     0.0     
Read fail17     0.0     
Read fail18     0.0     
Read fail19     0.0     
At the end of DHT read freeRam =5281
23.4,24.1,23.5,24.1,23.5,24.0,23.6,24.0,23.5,24.4,,0.0,23.7,24.0,23.3,24.5,23.0,26.4,23.0,26.2,23.1,23.7,23.3,25.4,22.7,26.5,22.8,27.3,22.8,26.1,22.8,24.1,,0.0,,0.0,,0.0,,0.0
After Emoncms transmission freeRam =5230
Connecting to Emoncms...

Sent Transmission
freeRam =5281

According to the Adafruit freeRam function, I have over 5000 bytes separating the stack and the heap. I have also included the RTC library since the final sketch will have that included.

It continues to do the same thing over and over. The main transmission line is was about 266 characters long, the new transmission line is 174 since I moved the API key and preliminary stuff into the update function entirely.

Thanks.

Tim

Well, I am amazed at the silence on this. But, I think I found A soulution, it probably isn't THE best solution, but so far it appears to work.

While working on it last night I happened to notice that the GET call only worked once per session of the client. Once it closed a client and opened a new session, it would send the update.

So my fix at the moment is to client.stop after the transmission, and client.start before taking data for the next transmission. Since the data will only be transmitted every 10 minutes or so, it SHOULD be okay....I think

If there are any wise guru's out there that know a little more about the whole Ethernet interface want to chime in please do so.

Tim