Go Down

Topic: Delays and unsigned long (Read 3276 times) previous topic - next topic

Jim_Socks

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!

UKHeliBob

Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

GoForSmoke

Guess which one delay() is,

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



Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Jim_Socks

Firstly, way up top in the code is this:
Code: [Select]

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":
Code: [Select]
 
 
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:
Code: [Select]

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":
Code: [Select]

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:
Code: [Select]

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
Code: [Select]
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.

Jim_Socks

From the website link Goforsmoke posted:

Quote
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)?

Maltelec

Quote
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:

Code: [Select]

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.

GoForSmoke

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.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

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.

Maltelec

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.

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 ?
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

GoForSmoke


@ 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.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

wildbill


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.

holmes4

Or just make volume unsiged byte.

Mark

UKHeliBob

Code: [Select]
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 !
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

GoForSmoke


Or just make volume unsiged byte.

Mark


Still going to have trouble fitting 9250.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Go Up