Arduino crashes and reboots - Memory issues(?) / Guidance

Hi there.

I am working on building a weight scale which can send messages on preset timestamps, using an Arduino Uno and SIM900 board.

It was running well on previous versions of the code, in which every weight reading was sent right away in a message. But I wanted to send one message with 3 readings, and then the Arduino started crashing and rebooting as I observed in the Serial monitor.

I searched on the web for Arduinos crashing and rebooting, and it seems like a memory issue.
However, the memory used is on ~60% of both the program storage space and the dynamic memory.

I would be greatful to hear any solutions or guidance on how to correct/improve my code.

Thank you in advance.

Ektor

#include "LowPower.h"
#include "HX711.h"  //You must have this library in your arduino library folder
#include "DHT.h"
#include <OneWire.h>
#include <DallasTemperature.h>
#include "SIM900.h"
#include <SoftwareSerial.h>
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include "sms.h"
SMSGSM sms;
tmElements_t tm;

#define BUZZER 13
#define DOUT  A1
#define CLK  A0
#define DHTPIN  4
#define DHTTYPE DHT11
#define ONE_WIRE_BUS 5
#define GSM_ON 8
HX711 scale(DOUT, CLK);

DHT dht(DHTPIN, DHTTYPE);

OneWire oneWire(ONE_WIRE_BUS);

DallasTemperature sensors(&oneWire);

float calibration_factor = 42870; 

//Global variables
float h; // humidity
float t; // temperature
float w; // weight
float dif; // difference
float lastWeight = 0;
char scaleName[20] = "ZYGARIA 2";
char rTime[5];

int hour1 = 5; int min1 = 31; //09.00
int hour2 = 5; int min2 = 32; //16.00
int hour3 = 5; int min3 = 33; //22.00


boolean started = false;
char n[20];

//debug begin
char sms_position;
char phone_number[20]  = "xxxxxxxxxx";
char sms_text[160];

void setup() {
  Serial.begin(9600);

  pinMode(GSM_ON, OUTPUT);
  pinMode(BUZZER, OUTPUT);

  //  Save Power by writing all digital IO LOW
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);

  dht.begin();
  sensors.begin();

  scale.set_scale();
  scale.tare(); 

  long zero_factor = scale.read_average(); 

  readSensors();
  LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
  readSensors();

}

void loop() {
  readTime();
  if ((tm.Day == 7) && (tm.Month == 5) && (tm.Hour == 0) && (tm.Minute == 0)) {
    refillSMS();
  }

  if ((tm.Hour == hour1) && (tm.Minute == min1)) {
    readSensors();
    smsTextNew();
  }

  if ((tm.Hour == hour2) && (tm.Minute == min2)) {
    readSensors();
    smsTextConcat();
  }

  if ((tm.Hour == hour3) && (tm.Minute == min3)) {
    startGSM();

    scale.power_up();

    readSensors();
    smsTextConcat();

    sendSMSread();

    GSMpowerDown();

    scale.power_down();
  }

  if (Serial.available()) {
    char temp = Serial.read();
    if (temp == '+' || temp == 'a')
      calibration_factor += 10;
    else if (temp == '-' || temp == 'z')
      calibration_factor -= 10;
    else if (temp == 's')
      calibration_factor += 100;
    else if (temp == 'x')
      calibration_factor -= 100;
    else if (temp == 'd')
      calibration_factor += 1000;
    else if (temp == 'c')
      calibration_factor -= 1000;
    else if (temp == 'f')
      calibration_factor += 10000;
    else if (temp == 'v')
      calibration_factor -= 10000;
    else if (temp == 't')
      scale.tare();  //Reset the scale to zero
  }

  for (int j = 0; j <= 5; j++) {
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
    LowPower.powerDown(SLEEP_250MS, ADC_OFF, BOD_OFF);
  }
}

void readSensors() {
  sensors.requestTemperatures(); 
  scale.set_scale(calibration_factor);

  h = dht.readHumidity();
  t = sensors.getTempCByIndex(0);
  w = scale.get_units(10);

  dif = w - lastWeight;
  lastWeight = w;
}

void startGSM() {
  if (!started)
  {
    Serial.println(F("GSM Shield testing."));
    if (gsm.begin(4800))
    {
      Serial.println(F("\nstatus=READY"));
      started = true;
      for (int j = 0; j < 2; j++) {
        digitalWrite(BUZZER, HIGH);
        LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);
        digitalWrite(BUZZER, LOW);
        LowPower.powerDown(SLEEP_120MS, ADC_OFF, BOD_OFF);
      }
    }
    else {
      Serial.println(F("\nstatus=IDLE"));
    }
  }
}

void sendSMSread() {
  if (started) {
    Serial.println(sms_text);
    delay(100);

    if (sms.SendSMS(phone_number, sms_text)) {
      Serial.println(F("\nSMS sent OK"));
      for (int j = 0; j < 2; j++) {
        digitalWrite(BUZZER, HIGH);
        LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF);
        digitalWrite(BUZZER, LOW);
        LowPower.powerDown(SLEEP_500MS, ADC_OFF, BOD_OFF);
      }
    }
  }
}

void smsTextNew() {
  char wbuffer[7];
  dtostrf(w, 7, 3, wbuffer);
  char dbuffer[7];
  dtostrf(dif, 7, 3, dbuffer);
  char tbuffer[5];
  dtostrf(t, 5, 2, tbuffer);
  char hbuffer[5];
  dtostrf(h, 5, 2, hbuffer);

  strcpy(sms_text, scaleName);
  strcat(sms_text, ",");
  strcat(sms_text, rTime);
  strcat(sms_text, ",R:");
  strcat(sms_text, wbuffer);
  strcat(sms_text, "kg,D:");
  strcat(sms_text, dbuffer);
  strcat(sms_text, "kg,T:");
  strcat(sms_text, tbuffer);
  strcat(sms_text, ",H:");
  strcat(sms_text, hbuffer);

  Serial.println(sms_text);
}

void smsTextConcat() {
  char wbuffer[7];
  dtostrf(w, 7, 3, wbuffer);
  char dbuffer[7];
  dtostrf(dif, 7, 3, dbuffer);
  char tbuffer[5];
  dtostrf(t, 5, 2, tbuffer);
  char hbuffer[5];
  dtostrf(h, 5, 2, hbuffer);

  strcat(sms_text, ",");
  strcat(sms_text, rTime);
  strcat(sms_text, ",R:");
  strcat(sms_text, wbuffer);
  strcat(sms_text, "kg,D:");
  strcat(sms_text, dbuffer);
  strcat(sms_text, "kg,T:");
  strcat(sms_text, tbuffer);
  strcat(sms_text, ",H:");
  strcat(sms_text, hbuffer);
  
  Serial.println(sms_text);
}

void GSMpowerDown() {
  digitalWrite(GSM_ON, HIGH);
  delay(2000);
  digitalWrite(GSM_ON, LOW);
  delay(2000);
  started = false;
  Serial.println("GSM Power Down");
  delay(100);
}

void refillSMS() {
  if (sms.SendSMS("1252", "91")) {
    Serial.println(F("\nRefill SMS sent OK"));
  }
}

void readTime() {

  if (RTC.read(tm)) {
    char timeText[100];
    strcpy(timeText, "Ok, Time = ");
    char timeTemp[2];
    sprintf(timeTemp, "%02d", tm.Hour);
    strcat(timeText, timeTemp);
    strcpy(rTime, timeTemp);
    strcat(timeText, ":");
    strcat(rTime, ":");
    sprintf(timeTemp, "%02d", tm.Minute);
    strcat(timeText, timeTemp);
    strcat(rTime, timeTemp);
    strcat(timeText, ":");
    sprintf(timeTemp, "%02d", tm.Second);
    strcat(timeText, timeTemp);
    strcat(timeText, ", Date (D/M/Y) = ");
    sprintf(timeTemp, "%02d", tm.Day);
    strcat(timeText, timeTemp);
    strcat(timeText, "/");
    sprintf(timeTemp, "%02d", tm.Month);
    strcat(timeText, timeTemp);
    strcat(timeText, "/");
    char yearTemp[4];
    sprintf(yearTemp, "%04d", tmYearToCalendar(tm.Year));
    strcat(timeText, yearTemp);
    Serial.println(timeText);
    delay(100);
  }
  else {
    if (RTC.chipPresent()) {
      Serial.println(F("The DS1307 is stopped.  Please run the SetTime"));
      Serial.println(F("example to initialize the time and begin running."));
      Serial.println();
    }
    else {
      Serial.println(F("DS1307 read error!  Please check the circuitry."));
      Serial.println();
    }
  }
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

Sketch uses 20402 bytes (63%) of program storage space. Maximum is 32256 bytes.
Global variables use 1245 bytes (60%) of dynamic memory, leaving 803 bytes for local variables. Maximum is 2048 bytes.

Is the rtime array large enough ?

UKHeliBob:
Is the rtime array large enough ?

I guess so. It's just the time - hour and minutes in the "hh:mm" form (e.g. "14:00").
Do you think that 5 characters are not enough?

Ektor

Ettore_M:
I guess so. It's just the time - hour and minutes in the "hh:mm" form (e.g. "14:00").
Do you think that 5 characters are not enough?

Ektor

Don't forget the null character.

Don't forget the null character.

He did.

I was using my 'phone when I replied so it was not so easy to check the code, but writing outside of the array bounds seemed a likely candidate given the symptoms

Yeah guys. I guess you're right. Though it is more that I didn't know about the null character. I was searching the web yesterday and my eye caught something about null characters.

Also, I saw something about the use of memset to "zero" all the characters inside of a character array before starting adding any data into it. Is this something that I should be using?

Thank you for your info.

Ektor

I saw something about the use of memset to "zero" all the characters inside of a character array. Is this something that I should be using?

Not necessary if you you use strcpy(), strcat() or sprintf() to populate the array because they add the terminating zero you. It can be useful if you are adding characters to the array

Using snprintf() will prevent the problem occurring if used with the correct parameters but in order for the length parameter to be correct it implies that you know what you are doing. It is still safer than sprintf() where strings of unexpected length are involved or where changes are made to strings in the program without considering the consequences.