Yet another freeze thread

Hey Community,

I got a problem with my code that I did alot of research on but still can’t find a solution.
I am using a DHT22, OLED and SD card module and trying to log temp and humidity.

After a seemingly random amount of time, the code execution freezes. I think I got a memory problem as the others that are using for example the String library (which I don’t).
So I probably got another problem in my code which I simply can’t find out.

Please quickly scan my code and give me some hints, as I am at a deadend currently :frowning:

#include <DHT.h>
#include <U8g2lib.h>
#include <DS3232RTC.h>
#include <TimeLib.h>
#include <Timezone.h>
#include <SPI.h>
#include <Wire.h>
#include <SD.h>

#define DHTPIN 2
#define DHTTYPE DHT22

#define DISPLAY_REFRESH_RATE 1000
#define READ_INTERVAL_DHT22 2000
#define READ_INTERVAL_RTC 900
#define SD_WRITE_INTERVAL 60000

#define OLED_WIDTH 128
#define OLED_HEIGHT 64

const int chipSelect = 4;

DHT dht(DHTPIN, DHTTYPE);

U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0);

File dataFile;

float humidity = 0.0f;
float temperature = 0.0f;

void setup() {
  Serial.begin(9600);
  setSyncProvider(RTC.get);
  dht.begin();
  u8g2.begin();
  SD.begin(chipSelect);
}

time_t getLocalTime() {
  static TimeChangeRule germanSummerTime = {"DEUS", Last, Sun, Mar, 2, 120};
  static TimeChangeRule germanWinterTime = {"DEUW", Last, Sun, Oct, 3, 60};
  static Timezone germanTime(germanSummerTime, germanWinterTime);
  time_t localTime = germanTime.toLocal(now());
  return localTime;
}

void readDht22() {
  static unsigned long previousMillis = 0;

  if (millis() - previousMillis > READ_INTERVAL_DHT22) {
    previousMillis = millis();
    readHumidity();
    readTemperature();
  }
}

void readHumidity() {
  float humdityReading = dht.readHumidity();
  if (isnan(humdityReading)) {
    return;
  }
  humidity = humdityReading;
}

void readTemperature() {
  float temperatureReading = dht.readTemperature(false);
  if (isnan(temperatureReading)) {
    return;
  }
  temperature = temperatureReading;
}

void writeToFile() {

  static unsigned long previousMillis = 0;

  if (millis() - previousMillis > SD_WRITE_INTERVAL) {
    previousMillis = millis();
    
    char buffer[60];
    
    dataFile = SD.open("readings.txt", FILE_WRITE);
    time_t currentTime = getLocalTime();
    sprintf(buffer, "%i.%i.%i - %02i:%02i:%02i",
      day(currentTime),
      month(currentTime),
      year(currentTime),
      hour(currentTime),
      minute(currentTime),
      second(currentTime));

    char humidityBuffer[10];
    char *humidityString = dtostrf(humidity, 2, 1, humidityBuffer);

    char temperatureBuffer[20];
    char *temperatureString = dtostrf(temperature, 2, 1, temperatureBuffer);

    strcat(buffer, ";"); 
    strcat(buffer, humidityString);
    strcat(buffer, ";");
    strcat(buffer, temperatureString);
    dataFile.println(buffer);
    dataFile.close();
    Serial.println(buffer);
  }
}

void draw() {
  static unsigned long previousMillis = 0;

  if (millis() - previousMillis > DISPLAY_REFRESH_RATE) {
    previousMillis = millis();

    u8g2.firstPage();
    do {
      drawHumidity();
      drawTemperature();
      drawTimeAndDate();
    } while (u8g2.nextPage());
  }
}

void drawHumidity() {
  char buffer[10];
  char *humidityString = dtostrf(humidity, 2, 1, buffer);
  strcat(humidityString, "%");

  u8g2.setFont(u8g2_font_trixel_square_tf);
  u8g2.drawStr(0, 63, humidityString);

  u8g2.setFont(u8g2_font_trixel_square_tf);
  u8g2.drawStr(0, 45, "Luftfeuchtigkeit");
}

void drawTemperature() {
  char buffer[20];
  char *temperatureString = dtostrf(temperature, 2, 1, buffer);
  strcat(temperatureString, "\xB0");

  u8g2.setFont(u8g2_font_trixel_square_tf);
  byte rightPosTempValue = OLED_WIDTH - u8g2.getStrWidth(buffer);
  u8g2.drawStr(rightPosTempValue, 63, temperatureString);

  u8g2.setFont(u8g2_font_trixel_square_tf);
  byte rightPosTempKey = OLED_WIDTH - u8g2.getStrWidth("Temperatur");
  u8g2.drawStr(rightPosTempKey, 45, "Temperatur");
}

void drawTimeAndDate() {
  char buffer[20];
  time_t currentTime = getLocalTime();
  byte hours = hour(currentTime);
  byte minutes = minute(currentTime);
  byte seconds = second(currentTime);
  sprintf(buffer, "%02i:%02i:%02i", hours, minutes, seconds);

  u8g2.setFont(u8g2_font_trixel_square_tf);

  byte centerPosTime = (OLED_WIDTH - u8g2.getStrWidth(buffer)) / 2;
  u8g2.drawStr(centerPosTime, 18, buffer);

  byte days = day(currentTime);
  byte months = month(currentTime);
  int years = year(currentTime);
  sprintf(buffer, "%i.%i.%i", days, months, years);

  u8g2.setFont(u8g2_font_trixel_square_tf);

  byte centerPosDate = (OLED_WIDTH - u8g2.getStrWidth(buffer)) / 2;
  u8g2.drawStr(centerPosDate, 32, buffer);
}

void loop() {
  readDht22();
  writeToFile();
  draw();
}

Thanks for every advice!

Kind regards
gnolle

How much RAM is left?

The sketch uses 81% of program memory. Global variables use 93% of dynamic memory, 338 byte for local variables left.

Using the MemoryAvailable library shows me 185 byte of SRAM are left.

Could this be the issue?

For the purpose of managing memory it may be better to make char arrays global rather than local, as in this function

void drawHumidity() {
  char buffer[10];

...R

Robin2: For the purpose of managing memory it may be better to make char arrays global rather than local, as in this function

void drawHumidity() {
  char buffer[10];

...R

Thank you Robin! Would defining them as static help with memory management or do they need to be defined globally?

gnolle: Thank you Robin! Would defining them as static help with memory management or do they need to be defined globally?

I was thinking of making them global so you could see more clearly how much memory you are using, Perhaps you can use the same array for two or three different purposes - you can't do that with static local arrays.

...R

Try to reduce RAM usage. If you need a temporary array, reuse/share it between functions.

You have multiple previousMillis, can you use one?

sprintf is quite large.

Thanks for the tips! I will try to reduce my RAM usage and check if that fixes the freezing! Reusing the arrays is a good idea, great!

So for anybody with the same problem.. It wasn't the shortage of SRAM. It actually was the DHT library causing the freeze. I don't know why but I switched the DHT library for this one: https://github.com/markruys/arduino-DHT and I am not facing any problems still even though it only saved one byte of SRAM. At other points in my research I heard that some interrupts used in some DHT library are causing problems.. Maybe this has something to do with this. So take care which DHT library you are using.

Anyway I am still not sure why my problem has been fixed but thanks for all that helped me.

Merry Christmas! gnolle

So I know this has been a little bit since the last post, but just wanted to chime in and say thank you. Thank you so much for continuing to post and post the solution you found because your solution also worked for me. Originally I was using the Adafruit DHT library, but this would hang up/freeze the program at random intervals. Just like in this post, I was chasing every route I knew of to try and fix the issue while placing my trust in the library, like all other libraries. After switching over to the library mentioned in your post, my program has been running for almost 24 hours now and still going. It also seems to have more features and more powerful than the Adafruit DHT library, to boot. So again, thank you so much.