Delays and unsigned long

Hi guys!

I am feeding a delay(); an unsigned long variable- but it acts funny with anything over int size (32k)

Do delays have trouble with large numbers that won't fit in an int?

(by "acting funny" I mean that if the number I feed it is over int size, it delays forever instead of stopping. I need it to delay anywhere between 3 seconds and 200 seconds. I am hoping to accomplish that simply by using an unsigned long- but it never stops delaying if I try anything over 32 seconds)

Thanks in advance!

Example code please.

Guess which one delay() is,

http://www.nongnu.org/avr-libc/user-manual/group__util__delay__basic.html

Firstly, way up top in the code is this:

byte drinkozarray[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
byte drinkozprevarray[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned long pumpcompensatearray[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

Then there is "pouramount" which is used inside of "countandpour", which is then used inside of "pour"

Here is "pouramount":

void pouramount(byte drink, byte &previousdrink, unsigned long &runtime, byte volume)
{
unsigned long pourdelay = 0;

 if(drink < previousdrink) {
    previousdrink = 0;
    runtime = 0;          //when I refill the bottle and reset the count, this should reset the added runtime too.
  }
    else if(drink >= previousdrink) {
    previousdrink = drink;
    runtime = runtime + 925 * volume;  //this should add 925ms for each full oz poured to account for lack in bottle backpressure
  }                                   // seeing as every 10 qtr oz I pour, the rate drops by about one qtr oz
 
 if (volume >= 1, volume < 32){
  pourdelay = volume * 9250;
  delay(pourdelay); //9250ms = one quarter ounce.  This way, when I type in my ingredients, I just tell it how many quarter oz to pour
 }
 
else if (volume = 0){
  delay(1157);               //This gives me a way to specify a "dash", or 1/8th ounce in a recipe, without getting all math crazy
  runtime = runtime + 116; 
}
else if (volume = 33){
  delay(3053); 
  runtime = runtime - 305250;  //This gives me a way to specify a "third", or 1/3rd ounce in a recipe, without getting all math crazy
  runtime = runtime + 305; 
}

delay(1250);  //this account for the pump spin-up time, while it's pumping liquid but none has yet come out of the nozzle
  delay(runtime); //this should add the extra backpressure acounting time to the runtime of the pump.

}

Here is countandpour:

void countandpour(byte array, byte volume) {
    if(volume >= 1, volume < 32) {
      drinkozarray[array] = drinkozarray[array] + volume;
    }
    else if(volume = 33) {
           drinkozarray[array] = drinkozarray[array] + 2; 
    }
    
   pouramount(drinkozarray[array], drinkozprevarray[array], pumpcompensatearray[array], volume);

}

and last but not least, here is "pour":

void pour(byte array, int drink, byte volume)
{
  switch (drink)
  {
  case vodkas:
    digitalWrite(latch, 0);
      lightredpour1();
      pour_vodka();
    digitalWrite(latch, 1);
      countandpour(array, volume);
    break;

  case rumlts:
    digitalWrite(latch, 0);
      lightredpour1();
      pour_rumlt();
    digitalWrite(latch, 1);
      countandpour(array, volume);
    break;

//etc, etc...

You'll notice that "pour" also calls "pour_vodka();" and "lightredpour1();"
The function with the liquor name just looks like this:

void pour_vodka()
{
  shiftOut(data, clock,MSBFIRST, shiftoutarray[1]); 
  shiftOut(data, clock, MSBFIRST, shiftoutarray[0]);
  shiftOut(data, clock, MSBFIRST, shiftoutarray[0]); 
  //vodka = vodka + volume;
}

void pour_rumlt()
{
  shiftOut(data, clock,MSBFIRST, shiftoutarray[2]); 
  shiftOut(data, clock, MSBFIRST, shiftoutarray[0]);
  shiftOut(data, clock, MSBFIRST, shiftoutarray[0]); 
}

//etc, etc...

And the "lightredpour();" function just controls effect lighting, changing it to red lights while pouring.

NOW to my original problem, which occurs inside "pouramount();"
I try to feed delay

unsigned long pourdelay = 0;
pourdelay = volume * 9250;
delay(pourdelay);

and if the result is anything over 32k, the delay just never ends. What is going on? (Additionally, I know my code is probably sloppy... I am still a dummy at this and I am working on that. Please try to stick to the delay problem I'm having instead of the ugliness of my code- as I would like it to work first before I spend lots of time optimizing something that doesn't work in the first place)

Oh and for those of you that have been helping me since the beginning- IT WORKS! I have booze in it, and it is pouring recipes! Until I fix this delay issue though, if a pour has to last longer than 32 seconds- it just pours until the end of time LOL.

From the website link Goforsmoke posted:

Thus, at a CPU speed of 1 MHz, delays of up to about 262.1 milliseconds can be achieved.

Since the uno is 16 Mhz, does that mean it can only delay for 4,193.6 milliseconds? That can't be right. You said to guess which one delay(); is, but I am not sure either one of them is? How can I use that in my situation (see above code)?

Thus, at a CPU speed of 1 MHz, delays of up to about 262.1 milliseconds can be achieved.

If that was true, 16MHz would be 16 milliseconds.

Try using the millis() function:

time = millis();
while (millis() <= time + 300000
{
}

That should wait until the CPU has counted up 300000 milliseconds. Pretty much the same as Delay only you are comparing values, not setting them.

Make sure time is unsigned long.

Then the Arduino version is extended at the least. What can I say? I almost never use delay().

Don't use delay(). Learn how BlinkWithoutDelay works. It will benefit you even after this project is done.

I'd also suggest using a sensor (if the stream will be lit red then a light detector might do) to tell when liquid is leaving the nozzle rather than waiting a default 1.25 seconds and some code to check how long that takes to warn you something may be wrong.

@ Maltelec:

I really would rather use Delay();

I don't want my CPU doing anything else while it's pouring, so delay works fine for me. Plus, once this is up and running it will never be unplugged- so when millis rolls over in 72 days I don't want to be surprised by any implications that could have anywhere in the miles-long code I wrote. Delay(); is simple, and doesn't rely on the 72-day long millis clock.

If I can make it work using delay();, I would like to.

If you used the Wait command, it won't do anything while it is waiting, it is just like Delay.

Only code within the Wait function is executed:

wait (While something =/!=/</>/<=/>= something else)
{
Do this while waiting
}

Carry on here after the Wait has ended.

When used correctly there is no problem with millis() rolling over.

As to not being able to use large values with the delay() function, it takes an unsigned long as its argument and they can go up to 4,294,967,295 so you have plenty of time on your hands. In your code what type of variable is volume ? 32 seconds is a very suspicious number. Could the delay actually be 32.767 seconds I wonder ?

If you Serial.print pourdelay just before the delay() what values do you get ?

Jim_Socks:
@ Maltelec:

I really would rather use Delay();

I don't want my CPU doing anything else while it's pouring, so delay works fine for me. Plus, once this is up and running it will never be unplugged- so when millis rolls over in 72 days I don't want to be surprised by any implications that could have anywhere in the miles-long code I wrote. Delay(); is simple, and doesn't rely on the 72-day long millis clock.

If I can make it work using delay();, I would like to.

It's 49.7-some days and rollover only makes that the longest interval you can measure.

If you use timing instead of delay you can run more than 1 gun with a single controller as well as check sensors to watch for problems. OTOH some people like their devices to be as dumb as possible since their people are always both observant and right. But me, I live in a different world.

UKHeliBob:
When used correctly there is no problem with millis() rolling over.

As to not being able to use large values with the delay() function, it takes an unsigned long as its argument and they can go up to 4,294,967,295 so you have plenty of time on your hands. In your code what type of variable is volume ? 32 seconds is a very suspicious number. Could the delay actually be 32.767 seconds I wonder ?

If you Serial.print pourdelay just before the delay() what values do you get ?

Looks like this is the culprit, volume is a byte. Try changing 9250 to 9250UL. If that doesn't fix it, cast volume to be unsigned long too.

Or just make volume unsiged byte.

Mark

Oh and for those of you that have been helping me since the beginning- IT WORKS!  I have booze in it, and it is pouring recipes!  
Until I fix this delay issue though, if a pour has to last longer than 32 seconds- it just pours until the end of time LOL.

Please accept my apologies. I meant to suggest that we don't fix the problem and all order a very large drink !

holmes4:
Or just make volume unsiged byte.

Mark

Still going to have trouble fitting 9250.

delay appears to use 16-bit arithmetic:

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

	while (ms > 0) {
		if (((uint16_t)micros() - start) >= 1000) {
			ms--;
			start += 1000;
		}
	}
}

You might have to write your own version that uses 32-bit arithmetic. I am guessing they did that so that a small delay, starting half-way through a millis() tick, would still be reasonably accurate.

Quote from: holmes4 on Today at 10:46:17 PM
Or just make volume unsiged byte.

Mark

Still going to have trouble fitting 9250.

??????????????

Mark

It looks to me as if that implementation will correctly handle delays that exceed 16 bits' worth of milliseconds. The sixteen-bit variable is only used for the micros() arithmetic. It'll cause the (truncated) value of micros() to roll over every 64K micros(), but the code handles rollover correctly.

I would expect delay() to work correctly for any unsigned long value passed to it, and I haven't seen any evidence that it doesn't.

holmes4:
Or just make volume unsiged byte.

Mark

The byte type IS unsigned.

Mmm - its the red wine again.

Mark