Board freezes up

Hello,

I'm having an issues with my project. I believe it is an issue with my code, but it could also be an issue with my power supply. Either way, I will appreciate any C&C on my code (I am not a frequent programmer and am very rusty with C++).

But first, a little background on my project. I am using a MKR GSM 1400 board to build an ultrasonic water level sensor which will take a reading once every hour and text me the results. Additionally, I have it set up take readings on command (it will take a reading and return that reading to anybody who sends it a text). I intend to eventually set this project up in a remote location and power it with a solar panel, but for now I am just running tests in my house.

Currently, I have been able to get it to run for maximum of 24 hours (I believe this record was reached using the 5v pin to power the distance sensor) when powered via the USB port (along with a 2500mA LiPo battery of course), but oftentimes it will freeze up at around the 8 or 9 hour mark. When I have ran tests with the board powered only by the battery, it seems to last only an hour or two before freezing up (this could just be coincidence since I have only ran a couple tests using battery power only).

Also note that I am using this distance sensor from Adafruit: Ultrasonic Distance Sensor - 3V or 5V - HC-SR04 compatible [RCWL-1601] : ID 4007 : $3.95 : Adafruit Industries, Unique & fun DIY electronics and kits

Below is my sketch.

// library which utilizes timekeeping hardware included with the MKR class Arduino boards
#include <RTCZero.h>

// library which manages the GSM modem included with the MKR GSM model Arduino board
#include <MKRGSM.h>

// there is no pinnumber set for this sim card, so it is left blank
#define PINNUMBER ""

// initialize GSM classes
GSM gsmAccess; 
GSM_SMS sms;

// set time and date of board initialization here
RTCZero rtc;
const byte day = 1;
const byte month = 1;
const byte year = 0;

const byte hrs = 0;
const byte mins = 0;
const byte sec = 0;

// create array to store the phone number of the incoming SMS 
char senderNumber[20];

// create variables to store distance sensor pin numbers
const int trigger = 0;
const int echo = 1;

// create boolean variable which will signify when it is time to send data
bool alarmTriggered = false;

// create string variable to store SMS messages which are received by the board
String command;


void setup() {
  // initialize real time clock and set time and date
  rtc.begin();
  rtc.setTime(hrs,mins,sec);
  rtc.setDate(day,month,year);

  // initialize serial connection and wait for it to connect before continuing
  Serial.begin(9600);
  //while(!Serial);     //uncomment this when using serial connection to test
  
  Serial.print("SMS water level monitor \nInitialized at: ");
  timeStamp();         // the timeStamp() function prints the time and date to the serial monitor
  Serial.println();

  // setup pins which are to be used by the distance sensor
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  // wait while board establishes connection with GSM network
  bool connected = false;
  while(!connected){
    if(gsmAccess.begin(PINNUMBER) == GSM_READY){
      connected = true;
    }
    else{
     Serial.println("Not Connected");
     delay(1000);
    }
  }
  Serial.println("GSM initialized");
  gsmAccess.lowPowerMode();
  Serial.println("GSM modem is in low power mode");
  
  rtc.setAlarmTime(00,01,00);
  rtc.enableAlarm(rtc.MATCH_MMSS);
  rtc.attachInterrupt(alarmMatch);
  
  Serial.println("Alarm set");
  Serial.println("Waiting for messages");
  
} 

void loop() {
  // when a text is recieved, read the text and return distance reading to sender
  if (sms.available()){
    // store sender number
    Serial.println("\nrequest recieved from: ");
    sms.remoteNumber(senderNumber, 20);
    Serial.println(senderNumber);
    
    // print sms message to the serial monitor
    int c;
    int i = 0;
    char com[20] = "";
    while ((c = sms.read()) != -1) {
      Serial.print((char)c);
      com[i] = (char)c;
      i++;
    }
    Serial.println();
    
    // convert character array to a sting which can be compared later
    command = String(com);
    Serial.println(command);
    
    Serial.println(" -- END OF MESSAGE");
    
    // delete message from modem memory
    sms.flush();
    Serial.println(" -- MESSAGE DELETED");


    // shutdown gsm modem and completely stop program if texted to do so.
    if (command=="Stop"){
      gsmAccess.shutdown();
      Serial.println("GSM Modem shutdown and program stopped");
      while(1); // Comment out if you want to continue to log data after shutdown
    }
    
    // print data to sms message and send
    sms.beginSMS(senderNumber);
    sms.print("Request recieved.\r");
    sms.print(getDistance(),1);
    sms.print(" cm  @ ");
    smsTimeStamp();
    sms.endSMS();
    
    Serial.println("Data Sent");
    
  }
  
  // check if alarm has been triggered. If true, get distance reading and send to me
  if (alarmTriggered){
    
    sms.beginSMS("--MY NUMBER GOES HERE--");
    sms.print(getDistance(),1);
    sms.print(" cm  @ ");
    smsTimeStamp();
    sms.endSMS();
    Serial.println("Data Sent");
    alarmTriggered = false;
    
  }

  // Debugging code
  //Serial.print(getDistance(),1);
  //Serial.print("  @ ");
  //timeStamp();
  //Serial.println();
  //delay(5000);
  
}

//function which returns distance of object or surface from the ultrasonic sensor
float getDistance(){
  long duration;
  float cm;
  digitalWrite(trigger, LOW);
  delayMicroseconds(5);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  duration = pulseIn(echo,HIGH);
  cm = (duration/2)/29.1;
  
  return cm;
}

// execute this function at the specified alarm time
void alarmMatch(){
  Serial.println();
  Serial.print("Alarm Match!  @ ");
  timeStamp();
  Serial.println();
  alarmTriggered = true;
}

// prints a time-stamp to the serial monitor
void timeStamp(){
  // Print date...
  print2digits(rtc.getDay());
  Serial.print("/");
  print2digits(rtc.getMonth());
  Serial.print("/");
  print2digits(rtc.getYear());
  Serial.print("  ");

  // ...and time
  print2digits(rtc.getHours());
  Serial.print(":");
  print2digits(rtc.getMinutes());
  Serial.print(":");
  print2digits(rtc.getSeconds());
}

// formats the date and time for the serial time-stamp function
void print2digits(int number) {
  if (number < 10) {
    Serial.print("0"); // print a 0 before if the number is < than 10
  }
  Serial.print(number);
}

// prints a time-stamp to the sms mesage
void smsTimeStamp(){
  // Print date...
  smsPrint2digits(rtc.getDay());
  sms.print("/");
  smsPrint2digits(rtc.getMonth());
  sms.print("/");
  smsPrint2digits(rtc.getYear());
  sms.print("  ");

  // ...and time
  smsPrint2digits(rtc.getHours());
  sms.print(":");
  smsPrint2digits(rtc.getMinutes());
  sms.print(":");
  smsPrint2digits(rtc.getSeconds());
}

// formats the date and time for the sms time-stamp function
void smsPrint2digits(int number) {
  if (number < 10) {
    sms.print("0"); // print a 0 before if the number is < than 10
  }
  sms.print(number);
}

I'm a bit rusty with Arduino this week, but I thought if you wanted to turn a char array into a string there were more steps involved than this code:

 // convert character array to a sting which can be compared later
   command = String(com);
   Serial.println(command);

Your code is compiling okay though. I haven't got my MKR GSM 1400 pugged in at the minute, but are you seeing the serial output you are expecting etc?

Do you have a diagram about how your unit's all connected up? I've seen some issues when people power sensors from VIO or similar, but you've indicated your's is from the 5V rail, so that should be okay....

Thanks for the reply! Sorry I for the late response. I took a break from this project because I was back in school, but I'm back to working on this project now.

The part of the code you linked seems to work fine and I've been getting all the serial output that i expected, but I'll be sure to look into that some more before I deploy to project.

I made some progress before I took my break, though. The main issue lied in my interrupt function. I was trying to do too much stuff inside the interrupt. Once I fixed that, I saw massive improvements. I ran the program for 3-4 days straight and it didn't lock up at all while powered by a USB port.

However, I am still having trouble when I take the project off the usb power and just run it with the battery. If I remember correctly, it will run for maybe 3 to 6 hours before it locks up. I will link my new code and my wiring diagram soon.

Also, at some point a changed the sensor's power source from the 5v rail to the 3.3v rail and it didn't seem to have any issues.

Im just guessing here, but if youre printing to serial but nothing is connected. Wouldnt the buffer be full and eventually die cause out of memory?

Add some #debug in your code.
So you compile without Serial.begin and all the Serial.prints

k4hvd:
Im just guessing here, but if youre printing to serial but nothing is connected. Wouldnt the buffer be full and eventually die cause out of memory?

You might be onto something there. I never really considered memory space. I could have sworn that I commented out all of the serial.prints and serial.begin before I ran my tests with just the battery. Though, maybe there is something else that is filling the memory?

Either way, I will try running another test with the arduino powered by an outlet and a USB cable with only the power pins (no data lines). If the board still freezes, then I should know for sure that it is my code and not the battery power. Right?

k4hvd:
Add some #debug in your code.

What do you mean by this? I'm not familiar with many debugging methods.

Here is an example.

#define DEBUG   //comment out to compile without 

//and place
#ifdef DEBUG
//before your Serial.prints.
Serial.print("...");
//and
#endif
//after.

UPDATED CODE:

#define DEBUG
//#define LOW_POWER
#define SMS
#define VCHECK
 
/// library which utilizes timekeeping hardware included with the MKR class Arduino boards
#include <RTCZero.h>

/// library which manages the GSM modem included with the MKR GSM model Arduino board
#include <MKRGSM.h>

/// there is no pinnumber set for this sim card, so it is left blank
#define PINNUMBER ""

/// initialize GSM classes
GSM gsmAccess; 
GSM_SMS sms;

/// set time and date of board initialization here
RTCZero rtc;
const byte day = 1;
const byte month = 1;
const byte year = 0;

const byte hrs = 0;
const byte mins = 0;
const byte sec = 0;

/// create array to store the number of the incoming SMS sender 
char senderNumber[20];

/// create variables to store pin numbers for distance sensor
const byte trigger = 0;
const byte echo = 1;

/// create boolean variable which will signify to the program when to send 
bool alarmTriggered = false;

void setup() {
  /// initialize real time clock and set time and date
  rtc.begin();
  rtc.setTime(hrs,mins,sec);
  rtc.setDate(day,month,year);

  /// initialize serial connection and wait for it to connect before continuing
  #ifdef DEBUG
    Serial.begin(9600);
    while(!Serial);
    
    Serial.print("SMS water level monitor \nInitialized at: ");
    timeStamp();
    Serial.println();
  #endif

  /// declare pins which are used by the distance sensor
  pinMode(trigger, OUTPUT);
  pinMode(echo, INPUT);

  /// wait while board establishes connection with GSM network
  #ifdef SMS
    bool connected = false;
    while(!connected){
      if(gsmAccess.begin(PINNUMBER) == GSM_READY){
        connected = true;
      }
      else{
        #ifdef DEBUG
          Serial.println("Not Connected");
        #endif
        delay(1000);
      }
    }
  #endif
  
  #ifdef DEBUG
    Serial.println("GSM initialized");
  #endif
  
  /// puts the GSM modem into low power mode
  #ifdef LOW_POWER
    gsmAccess.lowPowerMode();
    #ifdef DEBUG
      Serial.println("GSM modem is in low power mode");
    #endif
  #endif
  
  rtc.setAlarmTime(00,01,00);
  rtc.enableAlarm(rtc.MATCH_MMSS);
  rtc.attachInterrupt(alarmMatch);
  
  #ifdef DEBUG
    Serial.println("Alarm set");
    Serial.println("Waiting for messages\n");
  #endif
} 

void loop() {
  
  /// check battery voltage and print value to serial
  #ifdef DEBUG
    Serial.print(getDistance(),1);
    Serial.println(" cm");
    #ifdef VCHECK
      Serial.print(getVoltage(),2);
      Serial.println("V\n");
    #endif
  #endif
  
  /// checks if there are any incomming SMS messages. if there are, it will return 
  #ifdef SMS
    if (sms.available()){
      /// store sender number
      sms.remoteNumber(senderNumber, 20);
      
      /// completely stops program if message begins with the # character.
      if (sms.peek()=='#'){
        gsmAccess.shutdown();
        
        #ifdef DEBUG
          Serial.println("GSM Modem shutdown and program stopped");
        #endif
        
        while(1); // Comment out if you want to continue to log data to an SD card after shutdown
      }
      
      /// delete message from modem memory
      sms.flush();
      
      #ifdef DEBUG
        Serial.println(" -- MESSAGE DELETED");
      #endif
      
      /// print data to sms message and then send it to whoever made the request
      sendData(senderNumber,1);
    }
  #endif
  
  /// sends a message to me if the alarm was tripped
  if (alarmTriggered){
    
    #ifdef DEBUG
      Serial.println();
      Serial.print("Alarm Match!  @ ");
      timeStamp();
      Serial.println();
    #endif
    
    #ifdef SMS
      sendData("*my number goes here*",0);
    #endif
    
    alarmTriggered = false; // reset the alarm
    
  }
  
  delay(5000);
  
}

THE FUNCTIONS:

/// function which returns distance of object or surface from the ultrasonic sensor
float getDistance(){
  long duration;
  float cm;
  digitalWrite(trigger, LOW);
  delayMicroseconds(5);
  digitalWrite(trigger, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigger, LOW);

  duration = pulseIn(echo,HIGH);
  cm = (duration/2)/29.1;
  
  return cm;
}

/// execute this function at the specified alarm time
void alarmMatch(){
  
  alarmTriggered = true;
}

#ifdef DEBUG
/// prints a time-stamp to the serial monitor
void timeStamp(){
  // Print date...
  print2digits(rtc.getDay());
  Serial.print("/");
  print2digits(rtc.getMonth());
  Serial.print("/");
  print2digits(rtc.getYear());
  Serial.print("  ");

  // ...and time
  print2digits(rtc.getHours());
  Serial.print(":");
  print2digits(rtc.getMinutes());
  Serial.print(":");
  print2digits(rtc.getSeconds());
}
  
  // formats the date and time for the serial time-stamp function
void print2digits(int number) {
  if (number < 10) {
    Serial.print("0"); // print a 0 before if the number is < than 10
  }
  Serial.print(number);
}
#endif

#ifdef SMS
/// prints a time-stamp to the sms mesage
void smsTimeStamp(){
  // Print date...
  smsPrint2digits(rtc.getDay());
  sms.print("/");
  smsPrint2digits(rtc.getMonth());
  sms.print("/");
  smsPrint2digits(rtc.getYear());
  sms.print("  ");

  // ...and time
  smsPrint2digits(rtc.getHours());
  sms.print(":");
  smsPrint2digits(rtc.getMinutes());
  sms.print(":");
  smsPrint2digits(rtc.getSeconds());
}

// formats the date and time for the sms time-stamp function
void smsPrint2digits(int number) {
  if (number < 10) {
    sms.print("0"); // print a 0 before if the number is < than 10
  }
  sms.print(number);
}

void sendData(char number[20], bool requested){
  
    sms.beginSMS(number);
    if(requested){
      sms.print("Request recieved.\n");
    }
    sms.print(getDistance(),1);
    sms.print(" cm  @ ");
    smsTimeStamp();
    #ifdef VCHECK
      sms.print("\nBattery voltage: ");
      sms.print(getVoltage(),2);
      sms.print("V  ");
      //sms.print(sensorValue);
    #endif
    sms.endSMS();
          
    #ifdef DEBUG
      Serial.println("Data Sent\n");
    #endif
    
}
#endif

#ifdef VCHECK
/// returns the voltage of the connected battery
float getVoltage(){

  int sensorValue = analogRead(ADC_BATTERY);  // reads the voltage on the analog input pin ADC_BATTERY
  
  float voltage = sensorValue * (4.05 / 1023.0);  // convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 4.05V):
  
  #ifdef DEBUG
    Serial.println(sensorValue);
  #endif

  return voltage;
}
#endif

This code seems to be working great so far, but i'm still doing the long-term test (powered by usb from a wall socket).

I'm still having that issue with the board dying after about 11-12 hours when using only battery power, but i'm fairly sure that it's just the battery dying. The battery tops out at about 4.05v and the board dies when it gets to around 3.8v. I'm going to upgrade from a 2500mAh battery to a 4400mAh or a 6600mAh battery and then see how long it lasts. I'll also probably check the current consumption and see if it that supports my theory.