Looking for help with a bit of my code that's really got me puzzled!
I've got a Nano running an SSD1309 128 x 64 OLED using SPI. It's job is to count up in 0.1 seconds to a certain value whilst an input (pumpPin, D7) is true, then to hold that displayed value for 15 seconds if it hasn't changed, before resetting the counter to zero. Typically it's expected to only count for 30 seconds or so, then rest at 0 for minutes at a time.
Upon the input being active for 5 seconds or more an output (pumpActivePin, D6) gets pulled low for an external interface to log the event. -not currently connected.
Testing this program everything seems to work just fine! It's repeatable and works just as intended. But when left powered on for typically 10 to 30 minutes, a different and seemingly random failure will occur:
-
The LED on the Nano from pin 13 will stop flashing and extinguish. The display will then freeze, displaying whatever it last displayed.
-
The LED on the Nano from pin 13 will stop flashing and extinguish. The display will then go blank.
-
The LED on the Nano from pin 13 will keep flashing, but the display goes blank. Can confirm 5V is still present on the VCC pin of the display at this time.
A press of the reset button or reset of power to the unit rectifies any of these issues.
The failures will occur regardless of whether or not the input (pumpPin) is being triggered.
My suspicions are that I've either made a complete goof of the use of millis(), or something in the U8G2 library is doing something funky.
I've tried different Nano boards and displays in case there's a hardware glitch but no change in performance..
Code for reference. Hopefully it's not too horrendous to look at!
#include <Arduino.h>
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
U8G2_SSD1309_128X64_NONAME0_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
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;
void setup() {
pinMode(pumpPin, INPUT);
pinMode(pumpActivePin, OUTPUT);
digitalWrite(pumpActivePin, HIGH);
count = initialCount;
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_fub42_tn);
u8g2.setCursor(5,62);
u8g2.print(count,1);
u8g2.sendBuffer();
}
void loop() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_9x15_tf);
u8g2.drawStr(19,12, "PUMP TIMER");
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
}