// For: https://forum.arduino.cc/t/arduino-nano-freezing-randomly-after-a-few-minutes/1092485
// This Wokwi project: https://wokwi.com/projects/357197433569459201
//
// Changed display to I2C for Wokwi
// Removed #include <Arduino.h>
// Added freeMemory() function from Adafruit.
// Added Serial Monitor.
// Added a Free Memory millis-timer, every 2 seconds, to demonstrate a millis-timer.
// Moved text "PUMP TIMER" to setup().
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
// Wokwi has no SPI display, changed to I2C
// U8G2_SSD1309_128X64_NONAME0_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
int pumpPin = 7;
int pumpActivePin = 6;
unsigned long prevMillis;
unsigned long curMillis = 0;
unsigned long lastMillis;
float count;
float initialCount = 0.0;
boolean pumpActive;
boolean hasTriggered;
unsigned long previousMillisFreeMemory;
const unsigned long intervalFreeMemory = 2000;
void setup() {
pinMode(pumpPin, INPUT);
pinMode(pumpActivePin, OUTPUT);
digitalWrite(pumpActivePin, HIGH);
Serial.begin(115200);
count = initialCount;
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_fub42_tn);
u8g2.setCursor(5, 62);
u8g2.print(count, 1);
u8g2.sendBuffer();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_9x15_tf);
u8g2.drawStr(19, 12, "PUMP TIMER");
}
void loop() {
unsigned long currentMillis = millis();
// ##########################################################
// ## ##
// ## A millis-timer to show the free memory ##
// ## on the Serial Monitor ##
// ## ##
// ##########################################################
if( currentMillis - previousMillisFreeMemory >= intervalFreeMemory)
{
previousMillisFreeMemory = currentMillis;
Serial.print( "Free Memory: ");
Serial.print( freeMemory());
Serial.println( " bytes");
}
if (digitalRead(pumpPin) == LOW) {
u8g2.setFont(u8g2_font_fub42_tn);
u8g2.setCursor(5, 62);
u8g2.print(count, 1);
u8g2.sendBuffer();
}
curMillis = millis();
// if one tenth of a second has passed
if (((curMillis - prevMillis) >= 100) && (digitalRead(pumpPin) == HIGH)) {
curMillis = millis();
prevMillis = (millis() - 4); // Adjust this as required to get time correct (speeds up by 4ms per tick)
count += 0.1;
u8g2.setFont(u8g2_font_fub42_tn);
u8g2.setCursor(5, 62);
u8g2.print(count, 1);
u8g2.sendBuffer();
}
// If the pump has been running for 5 seconds or more, trigger the output to go LOW
if (count >= 5 && hasTriggered == 0) {
digitalWrite(pumpActivePin, LOW);
hasTriggered = 1; // Flag operation so this only has one falling edge per timer cycle
}
// Hold value on screen for 15 sec if it hasn't changed, isn't zero and the pump is not running
if (((curMillis - prevMillis) >= 15000) && (digitalRead(pumpPin) == LOW) && count != 0) {
resetCounter();
}
}
// Reset the counter, output and flag
void resetCounter() {
count = initialCount;
digitalWrite(pumpActivePin, HIGH);
hasTriggered = 0; // Reset flag so it is ready to trigger again during following pump
}
// Reference:
// https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory#sram-370031
#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__
int freeMemory() {
char top;
#ifdef __arm__
return &top - reinterpret_cast<char*>(sbrk(0));
#elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
return &top - __brkval;
#else // __arm__
return __brkval ? &top - __brkval : &top - __malloc_heap_start;
#endif // __arm__
}