Delay(25*HOUR) function stopping short on Arduino Nano Every board

I've been working on a simple Arduino project where a button press will activate a 25 hour timer countdown before a servo turns 90 degrees. I'm a chemist and my idea was to automate an addition funnel valve to open up in the middle of the night or whenever I can't be there to turn the valve myself.

I also added program lines to make the onboard LED remain on during the timer count down and then blink once the servo turns for a visual que that everything worked as expected. This is my code.


#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int buttonPin = 2;  // the pin that the button is attached to
int buttonState = 0;  // variable for reading the button status
int buttonPressed = 0;  // variable to track if the button has been pressed
int servoPosition = 0; // variable to track the current position of the servo
const int ledPin = 13;
const unsigned long SECOND = 1000;
const unsigned long HOUR = 3600 * SECOND;

void setup() {
  myservo.attach(9);  // attached the servo to pin 9 to the servo object
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP); // sets the button pin as an input with internal pull-up resistor
  myservo.write(servoPosition); // move servo to the 0 degree at startup
  digitalWrite(ledPin, LOW);
}

void loop() {

  while (buttonPressed == 1 && servoPosition == 64) {
    digitalWrite(ledPin, LOW); // turn the LED on
    delay(1000); // wait for 1 second
    digitalWrite(ledPin, HIGH); // turn the LED off
    delay(1000); // wait for 1 second
  }

  buttonState = digitalRead(buttonPin); // read the state of the button - put your main code here, to run repeatedly:
  if (buttonState == LOW && buttonPressed == 0) { //if the button is pressed and not already pressed
    buttonPressed = 1; // set the buttonPressed variable to 1 to indicate the button has been pressed
    digitalWrite(ledPin, HIGH);
    delay(25 * HOUR); // wait for  3 hours 10800000, 10 seconds 10000, 3600000/hr, 93600000/26hr
    servoPosition = 64; // set the servo position to 90 degrees
    myservo.write(servoPosition); // move servo to 90 degrees
  }

}

This program works perfect on my Arduino Uno. However, the cheap Arduino Nano Every clones will not carry out the full 25 hour delay function. I keep coming back after ~ an hour to find the servo has turned early and the board's LED blinking.

During troubleshooting, I even changed the delay to 10 seconds, tested the program, everything worked as expected, and then reuploaded the program with the full 25 hour delay just to have the same result as before.

Any ideas why the program on the UNO works fine but the program on the NANO Every comes up short?

Try this way:

const unsigned long SECOND = 1000UL;
const unsigned long HOUR = 3600UL * SECOND;

......
delay(25UL * HOUR);

parameter of delay is in milliseconds

1 Like

Can you please provide a link to these devices.

What value do you get if you print 25 * HOUR?

I'm guessing you found a compiler bug.

My first guess would be crystal variations and the associated effect on timers and timing: a 1% difference in frequencies could result in a difference of 160,000 clock cycles.

You are talking about controlling a process down to the millisecond, where you are counting 90 million of those milliseconds. These devices just are not precision instruments.

https://www.amazon.com/dp/B07YQ56B6Q/ref=twister_B07YQ4PLXT?_encoding=UTF8&th=1

What would be the fix if it is a compiler bug? I have had problems getting the IDE to successfully upload the program. I usually have to try hitting upload several times before the upload goes through, or at least says its complete. I calked is up to a busy COM connection.

I made the UL edits, but no success.

What's shown on the Amazon page are genuine Nano Every boards from Arduino.

The boards with possible issues are the Thinary Nano Every which is based on a 4808 and used a custom version of the core.

The value of (25*HOUR) with your code on both a Nano Every and a Uno was 90000000 and the integer promotion was working.

However, there is a difference in the delay() functions in the core.

Uno core 1.8.6

void delay(unsigned long ms)
{
	uint32_t start = micros();

	while (ms > 0) {
		yield();
		while ( ms > 0 && (micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

megaavr core 1.8.8

void delay(unsigned long ms)
{
	uint32_t start_time = micros(), delay_time = 1000*ms;

	/* Calculate future time to return */
	uint32_t return_time = start_time + delay_time;

	/* If return time overflows */
	if(return_time < delay_time){
		/* Wait until micros overflows */
		while(micros() > return_time);
	}

	/* Wait until return time */
	while(micros() < return_time);
}

In the delay() for the nano every, I see this, which may be larger than a uint32_t
delay_time = 1000*ms;

The difference between the two delay functions needs some exploration(and explanation). MegaCoreX also uses the megaavr version of delay.

1 Like

Try this and move on. There may be some overhead so you may get a delay longer than 25hrs, but the Arduino timer is not exact anyway.

  for (int hour = 0; hour < 25; hour++) {
    for  (int second = 0; second < 3600; second++) {
      delay(SECOND);
    }
  }

Or you could try using the BlinkWithoutDelay example sketch changing
const long interval = 1000; //for
unsigned long interval = 90000000;
(not tested :yawning_face:)

@cattledog

	/* Calculate future time to return */
	uint32_t return_time = start_time + delay_time;   <<<<<<<<<

	/* If return time overflows */
	if(return_time < delay_time){

And this addition smells when it overflows.... as then the next if is immediately true.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.