delay() problem

I have a program (see attached) for a sensor-based alarm clock. I have a loop that controls a series of delays, but for some reason, the delays don’t work. The delays work fine when I plug in a concrete number, but not a variable. What could the problem be?

Here’s the problematic part of the code to which I’m referring:

for(int i = 0; i <= 28; i++){
Serial.println(“beginning the delay process”);

digitalWrite(musicboxPin, LOW);
digitalWrite(motor1APin, HIGH);
digitalWrite(motor2APin, LOW);
delay(1000);

digitalWrite(motor1APin, LOW);
delay(secondsPerDelay);
//delay(secondsPerDelay);

}

ChronoDotPorgram_alarmAlgorithm_withSensor_3.pde (6.85 KB)

Please post the complete code in a code block. This makes it easier to debug for us.

Your secondsPerDelay variable is declared somewhere else so we cannot see how it is declared and where.

Cheers

Noorman: Please post the complete code in a code block.

The full code was provided in the attached .pde.

ahhreeyell, when posting code (snippets even) please use the "code" tags. (The "#" button in the post editor.)

Saying something "doesn't work" does not really give any help. What do you mean by "doesn't work"? You have Serial.print()s in your code. What is the value that secondsPerDelay is being calculated to? (This is an example of explaining, "doesn't work." You already have debug information in your code, so tell us what you expected and what actually happened. e.g., I calculated a delay of 2500 seconds but the program doesn't delay that long.)

Sorry, I wrote that out in a hurry so I didn't really think too hard about what I was saying. You're absolutely right. Also, I'll include the code tags next time.

When I put a concrete value in the delay() function, then the program stops for the correct number of seconds (e.g. when I put in 5000, it stops for five seconds; when I put in 10000, it stops for ten, and so on and so forth), but when I enter the variable "secondsPerDelay," the delay always lasts for only about one second.

The "secondsPerDelay" variable is calculated from the time entered by the user, so it should vary every time the program is run, depending on what values the user enters.

ahhreeyell: The "secondsPerDelay" variable is calculated from the time entered by the user, so it should vary every time the program is run, depending on what values the user enters.

And based on your Serial.print statements, is the correct value being calculated?

      for(int i = 0; i <= 28; i++){
        Serial.println("beginning the delay process");

        digitalWrite(musicboxPin, LOW);
        digitalWrite(motor1APin, HIGH);
        digitalWrite(motor2APin, LOW);
        delay(1000);

        digitalWrite(motor1APin, LOW);
        delay(secondsPerDelay);
        //delay(secondsPerDelay);

      }

It looks to me like secondsPerDelay should be a loop counter. What output do you get, based on what input?

Suppose the user enters 25. What value is in secondsPerDelay? The delay() function expects a value in milliseconds, so this code doesn’t make sense:

      totalDelayTime = (userTime*60) - 28;
      secondsPerDelay = totalDelayTime/28;

There is a multiply by 1000 missing (to convert seconds to milliseconds) and the magic number 28 needs explaining.

Yes, I just ran a test and all the values are printing correctly.

For example, suppose it’s 4:33pm and I want the alarm to go off at 5pm.
The program calculates that there are 27 minutes (or 1620 seconds) that must pass before the alarm goes off.
Then 28 seconds are subtracted from the 1620 (there is an object being lowered by a motor/pulley system that is detected by an IR sensor, and it takes approximately 28 seconds for it to lower before the sensor detects the appropriate distance and sets the alarm off). 1620 - 28 = 1592 seconds.
I want there to be a total of 28 delays, so I divide 1592 by 28, which gives us the number of seconds per delay (56 in this case).

All this calculates correctly, but the delays each last only one second and I have no idea why.

Thank you so much PaulS, boy do I feel stupid. I forgot to multiply my result by 1000 for milliseconds…derp. It's working now.

boy do I feel stupid

Been there, done that, got the t-shirt.

Is there any way to pause the program or time something without using delays? I don't want everything else in the program to stop completely.

Standard reply: see the Blink without delay tutorial, http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay.

All right, I tried switching out the delay() function for the millis() function and here’s the code I wrote, but the delays aren’t happening at all:

 totalDelayTime = (userTime*60) - 28;
      secondsPerDelay = (totalDelayTime/28)*1000;
      //debugging values:
      Serial.print("userTime:");      
      Serial.println(userTime);
      Serial.print("totalDelayTime:");      
      Serial.println(totalDelayTime);
      Serial.print("secondsPerDelay:");      
      Serial.println(secondsPerDelay);

      for(int i = 0; i <= 28; i++){
        Serial.println("beginning the delay process");

        if(currentMillis - previousMillis > interval){
          previousMillis = currentMillis;
          digitalWrite(musicboxPin, LOW);
          digitalWrite(motor1APin, HIGH);
          digitalWrite(motor2APin, LOW);
        }

        else if(currentMillis - previousMillis > secondsPerDelay){
          digitalWrite(motor1APin, LOW);
        }

      }

Oh also, the "interval" variable is a long set equal to 1000. All the variables in that code snippet are either from my program or taken straight from the BlinkWithoutDelay example.

The use of millis() is not a direct replacement for delay(). The delay() function blocks for a period of time. During that time, nothing else happens (except interrupt processing). If you need to do stuff while waiting, you need to restructure the application. The Blink Without Delay example show how to restructure your program, for a very simple case.

You have not adapted your program to properly make use of millis().

Think about how you would perform the actions that the Arduino is to perform, armed with only a watch (millis()), a pad of paper (variables in the Arduino sketch), and some tasks to perform.

When you have that defined, we can help you change that into code that the Arduino understands.

while(millis() - then < interval)
{
   // Do nothing
}

is just a long way of typing

delay(interval);

Oh, I forgot to add that these are the following values to which I set my variables:

long currentMillis = millis(); long previousMillis = 0;

previousMillis changes in the program though, as you can see from the code snippet I posted.

I just tried changing my if statements to while loops. Still isn’t delaying for the right amount of time. :confused:

    for(int i = 0; i <= 28; i++){
        Serial.println("beginning the delay process");

        while(currentMillis - previousMillis > secondsPerDelay){
          previousMillis = currentMillis;
          digitalWrite(motor1APin, LOW);
        }


        while(currentMillis - previousMillis > interval){
          previousMillis = currentMillis;
          digitalWrite(musicboxPin, LOW);
          digitalWrite(motor1APin, HIGH);
          digitalWrite(motor2APin, LOW);
        }

      }

It's not possible to tell from the code you posted what value is in previousMillis when that for loop starts. currentMillis is never updated in the loop, so, if currentMillis - previousMillis is less than secondsPerDelay the first while loop will never execute. If currentMillis - previousMillis is less than interval, the second while loop will never execute. The for loop, then, will do nothing. And do it very fast.

I might as well just upload my whole program all over again so you can see, but in any case, I declared previousMillis as 0 at the beginning of my program (before void setup()). I didn’t touch it throughout the program until that for loop, so presumably, it is still 0 there.

I also set currentMillis equal to the millis() function itself, so it does get updated.

ChronoDotPorgram_alarmAlgorithm_withSensor_4.pde (7.07 KB)

As Paul says. You mean something like:

previousMillis = millis ();

while(millis () - previousMillis <= secondsPerDelay){
          digitalWrite(motor1APin, LOW);
        }

Although I don’t see what that achieves over writing:

digitalWrite(motor1APin, LOW);
delay (secondsPerDelay);

Hopefully you mean “millisecondsPerDelay” anyway.

Thanks Nick, now it's working. For some reason however, it delays everything else in my program—e.g. constant readings of sensor values, the current time being reported by my RTC, etc. I have no idea why it's doing that. The reason I opted for millis() instead of delay() was because I didn't want everything else in my program to be paused.