Program hangs after an hour or so.

Hi Guys,

I have a program running on an Arduino Nano. It collects information from I2c sensors and it accepts commands from the Serial Port (either cable or Bluetooth) and either activates certain pins, or it writes a string to a MAX232 com device attached to a telescope.

Pretty much all of it is now tested and working except for the RS232 stuff.

However, if I leave it to run for a period of time, it hangs. Here is the code:

// Arduino pins

// ... code deleted for space

// Load Serial Protocols

// Second serial port for RS232
#include <SoftwareSerial.h>
SoftwareSerial SynscanSerial(11, 12); // Second RX, TX

// Focuser
const uint8_t pwmMainFocusOutPin_Cnst = 9; // PMW pin for main OTA (Out direction)
const uint8_t pwmMainFocusInPin_Cnst = 10; // PMW pin for main OTA (In direction)
int mainFocusSpeed = 255; // Reserved for speed of focuser of main OTA.

// DSLR Camera focuser  and shutter connected to digital pin 8
const uint8_t shutterPin_Cnst = 13; //

// Relay pin is controlled with D16 (A2). The active wire is connected to normally closed and common
const uint8_t relay1pin = 16;

/*
    To test view the output, point a serial monitor such as Putty at your Arduino.
    - If the Sensor Board has water droplets on it;
    "case 0" will be activated and " Rain Warning " will be sent to the serial monitor.
    - If the Sensor Board is dry;
    "case 1" will be activated and " Not Raining " will be sent to the serial monitor.
*/
// lowest and highest sensor readings:
const uint8_t sensorMin = 0;  // sensor minimum
const int sensorMax = 1024;  // sensor maximum

// Analogue pins
const uint8_t WindSensorPin = A1;      //  // speed km/h

// ****************** I2C **********************************************************************************
// A4, A5
// Setup RTC REAL TIME CLOCK
#include "RTClib.h"
RTC_DS1307 RTC;

#define DRAW_DELAY 118
#define D_NUM 47
bool rtcAvail = 0;
DateTime now ;

// initialize the library with the numbers of the interface pins
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

const byte customChar[8] = {
  0b00100,
  0b10110,
  0b01101,
  0b00110,
  0b00110,
  0b01101,
  0b10110,
  0b00100
};

// Load OLED headers
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4 // not used / nicht genutzt bei diesem Display
Adafruit_SSD1306 oled(OLED_RESET);

// BME 280 settings
#include <Adafruit_BME280.h>
#define BME280_ADDRESS (0x76)
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C
const float C2K = 273.15; // Convert degrees C to K;
bool bmeAvail = 0;

// Load MLX headers - IR Temp
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();

float envtempCflt = 0; // Floating point local temperature in ambient evnvironment
float skytempCflt = 0; // Floating point sky temperature from IR
float dewpointCflt = 0; // Floating point dewpoint
float humFlt = 0; // Floating point humidity
long int presFlt = 0; // Integer pressure pascals

//  Pins A7 used for Satellite millivolt readings.
const int mVoltPi_Const = A7;      // Analogue pin (7) for millivolt reading.

// Wind Variables
// Anemometer
volatile unsigned long Rotations; // cup rotation counter used in interrupt routine
volatile unsigned long ContactBounceTime; // Timer to avoid contact bounce in interrupt routine

char opcode[13] = "";
char param[3] = "";
char yyyy[5] = "20";

#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else // __ARM__
extern char *__brkval;
#endif // __arm__
bool memPrint = 1;

void setup()   {

  // initialize led pin as an output.
  pinMode(shutterPin_Cnst, OUTPUT);

  // Initialise Serial connection
  Serial.begin(9600);  //57600, SERIAL_8N1
  //Wait for serial port to connect. Needed for Leonardo only
  while (!Serial);

  // set the data rate for the SoftwareSerial port
  SynscanSerial.begin(4800);
  SynscanSerial.println('V');
  // Initialise protocols
  Wire.begin();
  // Initialise MLX
  mlx.begin();
  // Initialise BME280
  // (you can also pass in a Wire library object like &Wire2)
  if (!bme.begin()) {
    Serial.println(F("BME:0"));
  } else {
    bmeAvail = 1;
  }
  // Initialise RTC
  RTC.begin();
  // Check to see if the RTC is keeping time.  If it is, load the time from your computer.
  if (! RTC.isrunning()) {
    Serial.println(F("RTC:0"));
    RTC.adjust(DateTime(__DATE__, __TIME__));
  } else {
    rtcAvail = 1;
  }

  lcd.init(); //initialize the lcd
  lcd.backlight();// turn on the backlight;
  // lcd.noBacklight();//turn off the backlight;
  // Initialise OLED
  // initialize with the I2C addr 0x3C / mit I2C-Adresse 0x3c initialisieren
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  pinMode(relay1pin, OUTPUT);
  digitalWrite(relay1pin, LOW);

  // Initialse focuspwm
  pinMode(pwmMainFocusInPin_Cnst, OUTPUT);
  pinMode(pwmMainFocusOutPin_Cnst, OUTPUT);
  setPwmFrequency(pwmMainFocusOutPin_Cnst, 8);
  setPwmFrequency(pwmMainFocusInPin_Cnst, 8);

  // Anemometer
  pinMode(WindSensorPin, INPUT);
  //  attachInterrupt(WindSensorPin, isr_rotation, RISING);

}

void loop() {

  if (memPrint) {
    Serial.println(freeMemory());
  }
  if (bmeAvail) {
    presFlt = bme.readPressure();
    humFlt = bme.readHumidity();
    envtempCflt = bme.readTemperature();
    dewpointCflt = calcDewpoint(humFlt, envtempCflt);
  }
  skytempCflt = mlx.readObjectTempC();
  if (rtcAvail) {
    now = RTC.now();
  }
  if (SynscanSerial.available()) {
    Serial.write(SynscanSerial.read());
  }
  if (Serial.available() > 0 ) {
    //Received something
    // if (Serial.available() > 0 ) {
    Serial.readBytesUntil("#", opcode, 12);
    strncpy(param, opcode + 2, 2);
    Serial.println(opcode);
    lcd.setCursor(0, 0);
    lcd.println(opcode);

    if (strncmp(opcode, "RS", 2) == 0) {
      SynscanSerial.print(opcode + 2);
    }
    
// ... code deleted for space

    // Environment
    else if (strncmp(opcode, "EN", 2) == 0) {
      environmentJSON();
    }
  }
  // LCD I2C Display
  LCDDisplay();
  // OLED I2C Display
  OLEDDisplay();
  delay(1000);
}

int setSpeed(char param[3]) {
  int speedInt = atoi(param);

  Serial.println(param);
  Serial.println(speedInt);
  speedInt = 255 * speedInt / 99;
  return speedInt;
}
float calcDewpoint(float humi, float temp) {
  float k;
  k = log(humi / 100) + (17.62 * temp) / (243.12 + temp);
  return 243.12 * k / (17.62 - k);
}
void LCDDisplay() {
  lcd.setCursor(0, 0);

  //  lcd.print("At: ");
  //  lcd.print(presFlt);
  //  lcd.print(" Pa");
  lcd.setCursor(0, 1);
  if (now.hour() < 10) {
    lcd.print(0);
  }
  lcd.print(now.hour());
  lcd.print(':');
  if (now.minute() < 10) {
    lcd.print(0);
  }
  lcd.print(now.minute());
  lcd.print(':');
  if (now.second() < 10) {
    lcd.print(0);
  }
  lcd.print(now.second());

  lcd.setCursor(9, 1);

  if (memPrint) {
    lcd.print(F("M: "));
    lcd.print(freeMemory());
    lcd.print(F("B"));
  } else {
    lcd.print(F("S: "));
    lcd.print(int(skytempCflt + 273.15));
    lcd.print(F("K"));
  }

  lcd.createChar(0, customChar);
  //  lcd.home();
  lcd.setCursor(15, 0);
  lcd.write((uint8_t)0);
}
void OLEDDisplay() {

  oled.clearDisplay();

  
// ... code deleted for space

}
void environmentJSON() {


// ... code deleted for space

}

void setPwmFrequency(int pin, int divisor) {
  byte mode;

// ... code deleted for space

}
int freeMemory() {

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

I have attached a freeMemory monitor to it, but the memory appears to stay constant and does not diminish with time, so I’m not sure why it crashes.

Here’s a picture of the device and the memory output. The 609B free memory does not vary over the duration of operation.

I have edited the displayed code to keep within the 9000 character limit, but the entire .ino is attached.

Any ideas?

Thanks

Steve

I2C_Synscan_e2d1.ino (14.5 KB)

There are several places where you say "code deleted to save space".

Does the actual program as posted display the problem? If not the problem is probably in the deleted bits.

If a program is too long to include you can add the .ino file as an attachment.

A common cause for strange crashes is overwriting the end of an array.

...R

Robin2:
There are several places where you say “code deleted to save space”.

Does the actual program as posted display the problem? If not the problem is probably in the deleted bits.

If a program is too long to include you can add the .ino file as an attachment.

A common cause for strange crashes is overwriting the end of an array.

…R

Yes, I have attached the ino

First thing that comes to mind is that you overflow an array. And the first one that pop's out for me is 'yyyy'. I only see a strcat() when it comes to it. So stuff only gets concatenated to it, I never see it cleared... Nor do I see a length check. Which would mean it's easy to overflow...

So I would start by debugging the length of all strings when you want to write to them and/or use strcat() and len() etc to be sure you stay within bounds.

septillion: First thing that comes to mind is that you overflow an array. And the first one that pop's out for me is 'yyyy'. I only see a strcat() when it comes to it. So stuff only gets concatenated to it, I never see it cleared... Nor do I see a length check. Which would mean it's easy to overflow...

So I would start by debugging the length of all strings when you want to write to them and/or use strcat() and len() etc to be sure you stay within bounds.

It's true. Fantastic. I'll look into it.

septillion: First thing that comes to mind is that you overflow an array. And the first one that pop's out for me is 'yyyy'. I only see a strcat() when it comes to it. So stuff only gets concatenated to it, I never see it cleared... Nor do I see a length check. Which would mean it's easy to overflow...

So I would start by debugging the length of all strings when you want to write to them and/or use strcat() and len() etc to be sure you stay within bounds.

I've just replace those lines with:

  else if (strncmp(opcode, "YY", 2) == 0) {
      strncpy(yyyy, "20", 2);
      strcat(yyyy, param);
      RTC.adjust(DateTime(atoi(yyyy) , now.month(), now.day(), now.hour(), now.minute(), now.second()));        //set the year
    }

To reinitialise yyyy. Do you think that'll work?

Hmm... now it crashes after 11 loops, so obviously on the right track.

Regards,

Steve.

      strncpy(yyyy, "20", 2);
      yyyy[2] = '\0';
      strcat(yyyy, param);

It’s now running. I’m going to leave it until it crashes, today or tomorrow. If it’s still running tomorrow, I’ll bank that.

Thanks for your help.

Steve.

No, because it will not change it's value ;) There is already '2' and '0' in 'yyyy'. Key is in:

No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).

I also didn't check everything. I would still at least debug all writing to strings to be sure.

SteveBz:       strncpy(yyyy, "20", 2);       yyyy[2] = '\0';       strcat(yyyy, param);

It's now running. I'm going to leave it until it crashes, today or tomorrow. If it's still running tomorrow, I'll bank that.

Thanks for your help.

Steve.

For goodness sake, just (numerically) add 2000.

odometer: For goodness sake, just (numerically) add 2000.

Sadly, I don't know how to do that. I'm more of a Python type of guy.

Could you suggest some code?

Gratefully yours,

Steve.

septillion: No, because it will not change it's value ;) There is already '2' and '0' in 'yyyy'. Key is in:

I also didn't check everything. I would still at least debug all writing to strings to be sure.

So all I have to do is reset the array like this:

      yyyy[2] = '\0';

SteveBz:
Sadly, I don’t know how to do that. I’m more of a Python type of guy.

Could you suggest some code?

You’re kidding, right?

      RTC.adjust(DateTime( (2000 + atoi(param)) , now.month(), now.day(), now.hour(), now.minute(), now.second()));        //set the year

odometer: You're kidding, right?

      RTC.adjust(DateTime( (2000 + atoi(param)) , now.month(), now.day(), now.hour(), now.minute(), now.second()));        //set the year

Thanks for that. Excellent answer.

Steve