Arduino Mega crashes because webpage

Hello,

I have made a code for a customer,long story short: it reads temperature and sends signals to a relay board and prints the values on the lcd and webpage.

My arduino MEGA somehow crashes after sometimes days, minutes or hours. there is no pattern in the crashes and i cant figure out what goes wrong, is there anyone that can help?

I have in the past implemented the watchdog timer. but no succes.

The problem is in the ethernetshield do you guys have any idea?

the code:

//Programmeur: Mike Brink       |
//Project: Olthof Beton         |
//© 2021, P&B Techniek          |
//Uitgegeven in eigen beheer    
//------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|//
//Niets uit deze uitgave mag worden verveelvoudigd, opgeslagen in een geautomatiseerd gegevensbestand en/of openbaar gemaakt in enige vorm of op enige wijze, zonder toestemming. |//
//------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------|//
//Alle documentatie en handleidingen zijn aanwezig OP KANTOOR              |
//Technische gegevens:                                                     |
//Temp sensor: DS18B20 MAX: 125C - MIN: -55C                               |
//LCD Display: I2C 20X4 LCD                                                |
//Print: Arduino MEGA                                                      |
//Relay board 2 modules, en een screwshield.                               |
//-------------------------------------------------------------------------|

//De gebruikte libraries:
#include <Wire.h>
#include <DallasTemperature.h>
#include <OneWire.h>
#include <SPI.h>
#include <Ethernet.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>

//Ethernet shield setup:
//Het IP-ADRESS is afhankelijk van het lokale adres, check dit.
//Voer hieronder het MAC adress in van de controller en het IPADRESS.
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 11);
//Initialiseren van de EthernetServer library:
// (poort 80 is standaard voor HTTP, wij gebruiken een andere poort 25565!):
EthernetServer server(25565);

//LCD SETUP:
//Hieronder definiëren we het adress van de I2C Interface modules voor de displays.
//Wanneer er gebruik gemaakt word van een 16,2 scherm verander dan naar '16,2'
LiquidCrystal_I2C lcd1 = LiquidCrystal_I2C(0x27, 20, 4); //Dit is display 1
LiquidCrystal_I2C lcd2 = LiquidCrystal_I2C(0x26, 20, 4); //Dit is display 2
LiquidCrystal_I2C lcd3 = LiquidCrystal_I2C(0x25, 20, 4); //Dit is display 3

//Hieronder definiëren we de aansluitpin van de DS18B20 temperatuursensoren.
#define ONE_WIRE_BUS 3
#define TEMPERATURE_PRECISION 9
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

byte sensor1[8] = {0x28, 0x98, 0xA1, 0xBD, 0x13, 0x21, 0x01, 0x09};
byte sensor2[8] = {0x28, 0x1C, 0x6E, 0x0E, 0x00, 0x00, 0x00, 0x9E};
byte sensor3[8] = {0x28, 0xBA, 0x34, 0xFF, 0x12, 0x21, 0x01, 0xF8};
byte sensor4[8] = {0x28, 0x16, 0x0A, 0xF4, 0x12, 0x21, 0x01, 0x6B};
byte sensor5[8] = {0x28, 0xEE, 0x17, 0x58, 0x13, 0x21, 0x01, 0x38};
byte sensor6[8] = {0x28, 0xA9, 0x3F, 0x8C, 0x13, 0x21, 0x01, 0x01};
byte sensor7[8] = {0x28, 0xD9, 0x5D, 0x50, 0x13, 0x21, 0x01, 0x18};
byte sensor8[8] = {0x28, 0x05, 0x4E, 0x84, 0x13, 0x21, 0x01, 0x9C};
byte sensor9[8] = {0x28, 0xD7, 0x20, 0x96, 0x13, 0x21, 0x01, 0xBA};
byte sensor10[8] = {0x28, 0xCF, 0x7E, 0x3D, 0x13, 0x21, 0x01, 0x4A};
byte sensor11[8] = {};
byte sensor12[8] = {};
byte sensor13[8] = {};
byte sensor14[8] = {};
byte sensor15[8] = {};
byte sensor16[8] = {};
byte sensor17[8] = {};
byte sensor18[8] = {};
byte sensor[8] = {};
float tempC;

//Hieronder definiëren we de adressen van de digitale pinnen:
#define RELAY1 9
#define RELAY2 11
#define RELAY3 12
#define REQ_BUF_SZ   50

File webFile;               // the web page file on the SD card
boolean SWITCH_state[4] = {0};// stores the states of the Switches
char HTTP_req[REQ_BUF_SZ] = {0};// buffered HTTP req
float arduinoVCC = 4.88;   //guest stored as null terminated string
char req_index = 0; // index into HTTP_req buffer

const int TEMP_MAX = 58  ; // De grenswaarde voor de hoge temperatuur waarde.
const int TEMP_MIN = 51 ; // De grenswaarde voor de te lage temperatuur waarde.
const int TEMP_ERROR = -127 ; // De grenswaarde wanneer er een sensor in storing staat.
const int TEMP_ERRORRESET = 2; //De grenswaarde voor het automatisch resetten.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void setup() {
 Serial.begin(9600); //Begint het seriel communiceren met de serial monitor op 9600 baud
//Digitale pin defineren als uitgang.
 pinMode(9, OUTPUT);
 pinMode(10, OUTPUT); 
 pinMode(11, OUTPUT); 
 pinMode(12, OUTPUT); 
 sensors.begin();  

 // Ethernet connectie laten beginnen
 Ethernet.begin(mac, ip);  //Start de ethernet connectie en de server:
 // start de server
 server.begin();
 Serial.print("server is op adres: ");
 Serial.println(Ethernet.localIP());

 // initialize SD card
    Serial.println("Initializing SD card...");
    if (!SD.begin(4)) {
        Serial.println("ERROR - SD card initialization failed!");
        return;    // init failed
    }
    
    Serial.println("SUCCESS - SD card initialized.");
    // check for index.html file
    if (!SD.exists("index.htm")) {
         Serial.println("ERROR - Can't find index.htm file!");
        !SD.exists("index.htm");  
        !SD.exists("index.htm");   
        !SD.exists("index.htm");  
        return;// can't find index file
    }
    Serial.println("SUCCESS - Found index.htm file.");


 lcd1.init(); //Initialiseren van display 1
 lcd2.init(); //Initialiseren van display 2
 lcd3.init(); //Initialiseren van display 3
 
 lcd1.backlight(); //Zet de backlight aan voor display 1
 lcd2.backlight(); //Zet de backlight aan voor display 2
 lcd3.backlight(); //Zet de backlight aan voor display 3 

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() { 
 sensors.requestTemperatures();

 //Ingang melding PLC:
  if(sensors.getTempC(sensor3) > TEMP_MIN){
    //Serial.println("HOOG Signaal verzonden naar relais");
    digitalWrite(RELAY2, LOW); //Maakt de uitgang  hoog
  } else if(sensors.getTempC(sensor3) < TEMP_MIN){
    // Serial.println("LAAG Signaal verzonden naar relais");
    digitalWrite(RELAY2, HIGH); //Maakt de uitgang  laag
  }

if(sensors.getTempC(sensor7) > TEMP_MAX){
  // Serial.println("HOOG Signaal verzonden naar relais");
   digitalWrite(RELAY3, LOW); //Maakt de uitgang  hoog
 } else if(sensors.getTempC(sensor7) < TEMP_MAX){
  // Serial.println("LAAG Signaal verzonden naar relais");
   digitalWrite(RELAY3, HIGH); //Maakt de uitgang  laag
 }

  //Storing melding Visueel:
  if(sensors.getTempC(sensor7) == TEMP_ERROR){
    //Serial.println("HOOG Signaal verzonden naar relais");
    digitalWrite(RELAY1, HIGH); //Maakt de uitgang  hoog
  }
  else if(sensors.getTempC(sensor7) > TEMP_ERRORRESET){
  // Serial.println("LAAG Signaal verzonden naar relais");
   digitalWrite(RELAY1, LOW); //Maakt de uitgang  laag
 }
  if(sensors.getTempC(sensor3) == TEMP_ERROR){
    //Serial.println("HOOG Signaal verzonden naar relais");
    digitalWrite(RELAY1, HIGH); //Maakt de uitgang  hoog
  }
  else if(sensors.getTempC(sensor3) >TEMP_ERRORRESET){
  // Serial.println("LAAG Signaal verzonden naar relais");
   digitalWrite(RELAY1, LOW); //Maakt de uitgang  laag   
  }


  //Resultaten van de sensor uitprinten op de LCD 1.
  lcd1.setCursor (0, 0 );
  lcd1.print("P&B-Techniek");
  lcd1.setCursor (0, 1);
  lcd1.print("--------------------");
  lcd1.setCursor (0, 2);
  lcd1.print("Aanvoer-Vat: ");
  lcd1.print(sensors.getTempC(sensor7));
  lcd1.setCursor (0, 3);
  lcd1.print("Retour-Vat: "); 
  lcd1.print(sensors.getTempC(sensor3));
  
  //Resultaten van de sensor uitprinten op de LCD 2.
  lcd2.setCursor (0, 0 );
  lcd2.print("A-1:");  
  lcd2.print(sensors.getTempC(sensor9));
  lcd2.print("|");
  lcd2.print("R-1:");  
  lcd2.print(sensors.getTempC(sensor1));
  
  //Resultaten van de sensor uitprinten op de LCD 2.
  lcd2.setCursor (0, 1 );
  lcd2.print("A-2:");  
  lcd2.print(sensors.getTempC(sensor10));
  lcd2.print("|");
  lcd2.print("R-2:");  
  lcd2.print(sensors.getTempC(sensor8));
  
  //Resultaten van de sensor uitprinten op de LCD 2.
  lcd2.setCursor (0, 2 );
  lcd2.print("A-3:");  
  lcd2.print(sensors.getTempC(sensor6));
  lcd2.print("|");
  lcd2.print("R-3:");  
  lcd2.print(sensors.getTempC(sensor4));
  
  //Resultaten van de sensor uitprinten op de LCD 2.
  lcd2.setCursor (0, 3 );
  lcd2.print("A-4:");  
  lcd2.print(sensors.getTempC(sensor5));
  lcd2.print("|");
  lcd2.print("R-4:");  
  lcd2.print(sensors.getTempC(sensor2));

//Resultaten van de sensor uitprinten op de LCD 3.
  lcd3.setCursor (0, 0 );
  lcd3.print("A-5:");  
  lcd3.print("|");
  lcd3.print("R-5:");  

//Resultaten van de sensor uitprinten op de LCD 3.
  lcd3.setCursor (0, 1 );
  lcd3.print("A-6:");  
  lcd3.print("|");
  lcd3.print("R-6:"); 
    
//Resultaten van de sensor uitprinten op de LCD 3.
  lcd3.setCursor (0, 2 );
  lcd3.print("A-7:");  
  lcd3.print("|");
  lcd3.print("R-7:"); 
  
//Resultaten van de sensor uitprinten op de LCD 3.
  lcd3.setCursor (0, 3 );
  lcd3.print("A-8:");  
  lcd3.print("|");
  lcd3.print("R-8:"); 

  delay(10000);

  
  EthernetClient client = server.available();  // try to get client

    if (client) {  // got client?
        boolean currentLineIsBlank = true;
        while (client.connected()) {
            if (client.available()) {   // client data available to read
                char c = client.read(); // read 1 byte (character) from client
                // buffer first part of HTTP request in HTTP_req array (string)
                // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
                if (req_index < (REQ_BUF_SZ - 1)) {
                    HTTP_req[req_index] = c;          // save HTTP request character
                    req_index++;
                }
                // last line of client request is blank and ends with \n
                // respond to client only after last line received
                if (c == '\n' && currentLineIsBlank) {
                    // send a standard http response header
                    client.println("HTTP/1.1 200 OK");
                    // remainder of header follows below, depending on if
                    // web page or XML page is requested
                    // Ajax request - send XML file
                    if (StrContains(HTTP_req, "ajax_inputs")) {
                        // send rest of HTTP header
                        client.println("Content-Type: text/xml");
                        client.println("Connection: keep-alive");
                        client.println();
                        
                        // send XML file containing input states
                        XML_response(client);
                    }
                    else {  // web page request
                        // send rest of HTTP header
                        client.println("Content-Type: text/html");
                        client.println("Connection: keep-alive");
                        client.println("Refresh: 5000");
                        client.println();
                        webFile = SD.open("index.htm");        // open web page file
                        if (webFile) {
                            while(webFile.available()) {
                                client.write(webFile.read()); // send web page to client
                            }
                            webFile.close();
                        }
                    }
                    // display received HTTP request on serial port
                    Serial.print(HTTP_req);
                    // reset buffer index and all buffer elements to 0
                    req_index = 0;
                    StrClear(HTTP_req, REQ_BUF_SZ);
                    break;
                }
                // every line of text received from the client ends with \r\n
                if (c == '\n') {
                    // last character on line of received text
                    // starting new line with next character read
                    currentLineIsBlank = true;
                } 
                else if (c != '\r') {
                    // a text character was received from client
                    currentLineIsBlank = false;
                }
            } // end if (client.available())
        } // end while (client.connected())
        delay(5000);      // give the web browser time to receive the data
        client.stop(); // close the connection
    } // end if (client)
}

char StrContains(char *str, char *sfind)
// searches for the string sfind in the string str, returns 1 if string found or returns 0 if string not found.
{
    char found = 0;
    char index = 0;
    char len;
    len = strlen(str);
    if (strlen(sfind) > len) {
        return 0;
    }
    while (index < len) {
        if (str[index] == sfind[found]) {
            found++;
            if (strlen(sfind) == found) {
                return 1;
            }
        }
        else {
            found = 0;
        }
        index++;
    }
    return 0;
}

void XML_response(EthernetClient cl)
{
    float tempValOne = 0.0;
    float tempValTwo = 0.0;
    float tempValThree = 0.0;
    float tempValFour = 0.0;
    float tempValFive = 0.0;
    float tempValSix = 0.0;
    float tempValSeven = 0.0;
    float tempValEight = 0.0;
    float tempValNine = 0.0;
    float tempValTen = 0.0;
    float tempValEleven = 0.0;
    float tempValTwelf = 0.0;
    float tempValThirteen = 0.0;
    float tempValFourteen = 0.0;
    float tempValFiveteen = 0.0;
    float tempValSixteen = 0.0;
    float tempValSeventeen = 0.0;
    float tempValEightteen = 0.0;
    float tempValNineteen = 0.0;

    // Call sensor and calibration functions
    tempValOne = tempCalib1();
    tempValTwo = tempCalib2();
    tempValThree = tempCalib3();
    tempValFour = tempCalib4();
    tempValFive = tempCalib5();
    tempValSix = tempCalib6();
    tempValSeven = tempCalib7();
    tempValEight = tempCalib8();
    tempValNine = tempCalib9();
    tempValTen = tempCalib10();
    tempValEleven = tempCalib11();
    tempValTwelf = tempCalib12();
    tempValThirteen = tempCalib13();
    tempValFourteen = tempCalib14();
    tempValFiveteen = tempCalib15();
    tempValSixteen = tempCalib16();
    tempValSeventeen = tempCalib17();
    tempValEightteen = tempCalib18();
    tempValNineteen = tempCalib19();

    // Sending Gauge and Switch Values to webclient 
    cl.print("<?xml version = \"1.0\" ?>");
    cl.print("<inputs>");
    cl.print("<analog>");
    cl.print(tempValOne);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValTwo);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValThree);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValFour);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValFive);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValSix);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValSeven);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValEight);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValNine);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValTen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValEleven);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValTwelf);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValThirteen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValFourteen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValFiveteen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValSixteen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValSeventeen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValEightteen);
    cl.print("</analog>");
    cl.print("<analog>");
    cl.print(tempValNineteen);
    cl.print("</analog>");
    // Sending SWITCH states to dashboard 
    // SWITCH #1
    cl.print("<SW>");           
    if (SWITCH_state[0]) {
        cl.print("checked");
    }
    else {
        cl.print("unchecked");
    }
    cl.println("</SW>");
    // SWITCH #2
    cl.print("<SW>");
    if (SWITCH_state[1]) {
        cl.print("checked");
    }
    else {
        cl.print("unchecked");
    }
    cl.println("</SW>");    
    // SWITCH #3
    cl.print("<SW>");
    if (SWITCH_state[2]) {
        cl.print("checked");
    }
    else {
        cl.print("unchecked");
    }
    cl.println("</SW>");
    // SWITCH #4
    cl.print("<SW>");
    if (SWITCH_state[3]) {
        cl.print("checked");
    }
    else {
        cl.print("unchecked");
    }
    cl.println("</SW>");
    cl.print("</inputs>"); 
}


float tempCalib1() {
  float tempC = sensors.getTempC(sensor7);
  return tempC;
}
float tempCalib2() {
  float tempC = sensors.getTempC(sensor3);
  return tempC;
}
float tempCalib3() {
  float tempC = sensors.getTempC(sensor9);
  return tempC;
}
float tempCalib4() {
  float tempC = sensors.getTempC(sensor1);
  return tempC;
}
float tempCalib5() {
  float tempC = sensors.getTempC(sensor10);
  return tempC;
}
float tempCalib6() {
  float tempC = sensors.getTempC(sensor8);
  return tempC;
}
float tempCalib7() {
  float tempC = sensors.getTempC(sensor6);
  return tempC;
}
float tempCalib8() {
  float tempC = sensors.getTempC(sensor4);
  return tempC;
}
float tempCalib9() {
  float tempC = sensors.getTempC(sensor5);
  return tempC;
}
float tempCalib10() {
  float tempC = sensors.getTempC(sensor2);
  return tempC;
}
float tempCalib11() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib12() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib13() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib14() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib15() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib16() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib17() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib18() {
  float tempC = sensors.getTempC(sensor2);
}
float tempCalib19() {
  float tempC = sensors.getTempC(sensor2);
}

void StrClear(char *str, char length)
// sets every element of str to 0 (clears array)
{
    for (int i = 0; i < length; i++) {
        str[i] = 0;
    }
}

void printTemperature(DeviceAddress address) {
  // Fetch the temperature in degrees Celsius for device address:
  float tempC = sensors.getTempC(address);
  Serial.print(tempC);
}

You should move your temperatures to an array (to shorten the code which improves readability).

Learn to use the F() macro for string literals.

Can you explain what you think this code is used for?

A wiring diagram would help us to understand how your hardware looks.

You have three LCD displays connected by I2C. I guess that your I2C bus is over the acceptable length (~50cm).

I very briefly glanced at the code, I will try to look closer later. I had a similar issue communicating with a PLC. I used this chunk of code to make sure the read buffer was cleared out every time because it didn't all get read every time and would eventually fill the buffer and overflow I suspect. I also had another issue where I would try sending too much data too quickly so I put in the flush() function before my ethernet write command. Hope it helps.

  EIPlen = ethClient.available();

  while (EIPlen >= 200) {
    if (EIPlen > 200) {
      Serial.print(F("EIPlen: "));
      Serial.println(EIPlen);
    }
    ethClient.read(InBuffer, 200);
    EIPlen = ethClient.available();
  }

  ethClient.flush();
  ethClient.write(OutBuffer, 200);

Here is another issue (more than likely not related to the crash); this is just an example, there are more like that.

float tempCalib18()
{
  float tempC = sensors.getTempC(sensor2);
}

You promise to return a float but don't return anything. The tempC variable is NOT the same one as the global one.

hey Pylon,

That code is to launch the webpage that is loading from the sd card
The i2c lcd length is 30cm.

what should be there instead of the float? i'am a little bit "new" i have done a few projects but not everything is clear.

Hey apf,

what does this precisely do?

EIPlen = ethClient.available();

This gives you how many bytes have been received

  while (EIPlen >= 200) {

This will run in a loop while the number of bytes you have is at, or higher than what you desire. In my case, I'm always sending 200 bytes from the PLC.

    if (EIPlen > 200) {
      Serial.print(F("EIPlen: "));
      Serial.println(EIPlen);
    }

This is debug for me that more than the intended 200 bytes was received.

    ethClient.read(InBuffer, 200);
    EIPlen = ethClient.available();

If I have received more than 200 bytes, I will read it continuously in 200 byte chunks. This ensures the data is going into the correct registers and that I'm emptying the buffer every cycle of the processor. This prevents the buffer from filling up more and more and eventually over flowing.

  ethClient.flush();
  ethClient.write(OutBuffer, 200);

flush() prevents a write until the previous write is complete. The PLC code runs at a 100ms interrupt because of its own limitations so I don't want to overflow the PLC buffer either. Nor do I want to have two writes trying to happen at the same time on the Arduino side. Then I write the intended 200 byte packet to the PLC so it's always a known amount and the info can be parsed correctly.

Also, you don't have to send 200 bytes, you could just read as many as you need until you get to an end flag and discard the rest. You won't get the absolute most recent data, but it's not mission critical. You could also start a new read of the data and over write the previous. Point is, get the buffer cleared out. :wink:

By checking three times in a row if that file exists on the SD card? Sorry, that's garbage.

I guess that's 30cm to each LCD, makes 90cm in total. If you want that work you have to decrease the I2C speed otherwise you won't get it reliable.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.