Delay() doesn't respond above 1 minute of duration

Hiya!

I take “frames” (strings) to turn on led strips… I tested with seconds, but when I set a minute, the lights keep on for a long time (not a minute). I tried different ways but still don’t respond for a minute.

Next, the code that I tried and didn’t work:

void delaying(byte m){
for(unsigned int i=0; i<m; ++i)
delaySec(60);
}

or

void delayMin(byte m){
delay(m601000);
}

I saw that the delay() function has a parameter of type unsigned long that max value is 4,294,967,295, so far beyond the valueI’m setting (even though if overflows the max, it will come back to the minimum and therefore turn on in a shorter time)

Do you have any clue of this issue?

I research for miliseconds() function but I don’t think that it’s a solution here, I don’t mind that Arduino sleeps during this delay,

You will have to show your complete code or give an example that exhibits the problem.

For your second code snippet, you need to force the calculation to use unsigned longs (I don't suspect that to be the problem though); e.g m*60*1000UL

m*60*1000What do you think the result of this calculation is?

Wrong.

Ugh. What a mess.

@CharlieHdz, do not cross-post again.

sterretje: For your second code snippet, you need to force the calculation to use unsigned longs (I don't suspect that to be the problem though); e.g m*60*1000UL

Charlie never said what processor he was using. 16bit integer truncation issues are a big deal on the AVR but Integers are 32 bit on nearly all of the non AVR processors. (pic32, ARM, esp8266, STM32)

--- bill

Try

void delayMin(unsigned long m){
 delay(m*60*1000);
}

aarg: Try

void delayMin(unsigned long m){
 delay(m*60*1000);
}

Hiya,

aarg was partially right, the problem is that the parameter should be unsigned long!

A way that I see this is because in C the left operand(m) in this case, holds the value of the calculation with 60 and 1000... Because this number is bigger than the max that a byte can hold then it is truncated... I could solve with the aarg suggestion but the logic of the operation won't permit this... Therefore I can do something similar like this:

void delayMin(byte m){ unsigned long uM=m; delay(uM*60*1000); }

and it will work smootly! Thanks

void delayMin(byte m){
  delay(m*60*1000ul);
}

is a better way if you want to pass a byte

A way that I see this is because in C the left operand(m) in this case, holds the value of the calculation with 60 and 1000..

that’s a totally wrong way to see it. The computation will never be hold in m. Without indication it’s performed in a suitable format defaulting to int here (operation between byte and int, int wins)

Because this number is bigger than the max that a byte can hold then it is truncated

The operation is not done in a byte but in an int and 60*1000 will be precalculated and in a 16 bit int arduino like the uno, this is overflowing. So adding ul to a constant forces the whole calculation to be performed as unsigned long delivering the expected result

CharlieHdz:
Hiya,

aarg was partially right, the problem is that the parameter should be unsigned long!

A way that I see this is because in C the left operand(m) in this case, holds the value of the calculation with 60 and 1000…

But you would be wrong.
m being a 8 bit value is not what the issue is.
C does the calculation as an integer since none of the variables or constants involved are larger than an int.
(60 and 1000 are integers)
If you are are on an 8bit AVR processor, integers are 16 bits so the calculation is done with a 16 bit result and then the 16 bit result is converted to a 32 bit value before being passed to delay().

This is one of those gotchyas when using the AVR as the behavior is correct but often unexpected.

It was pointed out in the first response that if you made one of the constants a long then the calculation would be done as a long vs a an int. On an 8 bit AVR that can make a big difference.

J-M-L: void delayMin(byte m){   delay(m*60*1000ul); }

is a better way if you want to pass a byte that’s a totally wrong way to see it. The computation will never be hold in m. Without indication it’s performed in a suitable format defaulting to int here (operation between byte and int, int wins) The operation is not done in a byte but in an int and 60*1000 will be precalculated and in a 16 bit int arduino like the uno, this is overflowing. So adding ul to a constant forces the whole calculation to be performed as unsigned long delivering the expected result

I believe not, although I stand to be corrected. I think m*60 will first be calculated as an int. It is just good fortune that 60*255 doesn't overflow an int. So (again if I am not mistaken)

void delayMin(byte m){
  delay(m*60UL*1000);
}

would be a safer way

[edit] except for the fact that the optimization will create a constant 60000UL in either case, anyway.

No I believe the pre-processor will optimize and not keep 60*1000ul given it’s always to be calculated and replace by 60000 ( using unsigned long).

Given that byte is unsigned and delay expects an unsigned long using the L notation would force the evaluation of the expression as signed, and then convert it to unsigned to call the function. Not great in general but would not matter here as 255*60000 fits in a signed long easily

Just seen your edit :) yes you got it

IMO- delay that long is trouble. Your whole loop hangs right there for 60 sec at that checkpoint- each loop.

Int long is the quick fix. The better fix, use millis(). The key to millis- set a trigger time when things happen. Then do logic against current time to see if it’s time to do/check it again.