On-Off Timer

Hello everybody!
I am having a difficult time trying to program a quite simple On-Off timer with different times. I basically need it to do something like this:ù
-Turn on pin 4 for X seconds
-Turn pin 4 off and wait Y seconds
-Turn pin 5 on for X seconds
-Turn pin 5 off and wait Y seconds
As far as that goes, I have no big problems, but when I try to time the whole action, it just never stops.
For example, I would like the above routine to go on for let's say 30 seconds, with X time equal to 5 seconds and Y time equal to 3 seconds. I can do the routine, but I don't know how to make it last 30 seconds.
If necessary I can post the code here, but I wanted to see whether you could suggest a better way of doing this
Thanks in advance

(deleted)

If no one can see what you have done, how can anyone suggest a better way of doing it. Post the code, logical I would have thought.

Here you are.
It's the same code from my topic "Arduino WM Controller"

#define left 4 //left
#define right 5 //right

byte state = 0;
bool turnRight=false;//disables the motor from rotating right
const long work = 5000; //working time for the motor
const long pause = 3000; //pause time for the motor


unsigned long currentTime = 0;//current time

void setup()
{
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
}

void loop()
{
  if (state == 0)                           //if state equals 0 
  {
      if(turnRight==false)                    //and rotations to the right are not enabled
      {
        digitalWrite(left, HIGH);           //rotate to the left
      }
      else
      {
        digitalWrite(right, HIGH);             //if rotations to the right are enabled, turn right
      }
    if (millis() - currentTime >= work)     //if the working time is already over
    {
      if(turnRight==false)                    //and we have to turn off the motor 
      {
        digitalWrite(left, LOW);            //if it was turning to the left, turn off left
      }
      else
      {
        digitalWrite(right, LOW);              //else, turn off right
      }                
      state = 1;                            //set state to 1
      currentTime = millis();                 //reset time
    }
  }
  else if (state == 1)                      //if state equals 1
  {
    if (millis() - currentTime >= pause)      //and pause time is already over
    {
      currentTime = millis();                 //reset timer
      state = 0;                            //set state to 0
      if(turnRight==false)                    //if the motor was previously turning to the right
      {
        turnRight=true;                       //enable giraaDestra to make it rotate to the right next time
      }
      else
      {
        turnRight=false;                      //if it was turning to the right, disable turnRight to make it rotate to the left
      }
    }
  }
}

I've commented it a bit better and translated it from Italian to English.
However, if I try putting the code from "if(state==0)" to the end inside a "while(millis()-startTime<totalTime)" it just doesn't stop at the end. I know I have to declare the variables, this is justa an example.
So far, though, the code runs perfectly, so I really hope this is an easy to fix issue.

delay(1000); in microseconds might help. 1000 = 1 second, enter any amount you want.

lwhistler:
delay(1000); in microseconds might help. 1000 = 1 second, enter any amount you want.

delay() is blocking code, and should be avoided if possible.
As spykatcher2k said before: Look at blink without delay in the examples (that come with the IDE).
Leo..

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking.

It is best not to use the delay() function in anything other than a quick-and-dirty demo program.

...R

I didn't want to use delay() because I need this to work at the same time with other functions. I have already given a look at blink without delay and I don't have any big issues with millis(), it's just that this has been bothering me for weeks now. I can't incapsulate the cose in a millis() kind of control as I mentioned before, and I can't use delay(). What should I do?

Mattia9914:
What should I do?

Perhaps the 555 timer chip might be best for this project?

Mattia9914:
. I can't incapsulate the cose in a millis() kind of control as I mentioned before, and I can't use delay(). What should I do?

That is probably because you are thinking of this sort of code

while(millis()-startTime<totalTime)

Don't use WHILE - it is not much better than delay().

Did you study how it is done in the link I gave you Several Things at a Time?

...R

Not yet. I'll give it a closer look and see how it's accomplished.

Ok, so: form what I understand, the code uses states to actually turn on or off pins of the microcontroller.
As such, I could re-desing my code in a similar wayand use states that then trigger the output, rathcer than triggering the output myself, right? After that, I can wrap the whole thing inside a big " if(millis()-startTimer>totalTime)" and an "else{ stateRight=LOW; stateLeft=LOW}" and be done with it, right?

What you say in Reply #11 sounds roughly right - but the devil is in the detail. Try and see where you get to. If you have a problem post the code and explain what it actually does and what it should do.

...R

Mattia9914:
Ok, so: form what I understand, the code uses states to actually turn on or off pins of the microcontroller.
As such, I could re-desing my code in a similar wayand use states that then trigger the output, rathcer than triggering the output myself, right? After that, I can wrap the whole thing inside a big " if(millis()-startTimer>totalTime)" and an "else{ stateRight=LOW; stateLeft=LOW}" and be done with it, right?

When you have something to loop through like an array of pins, you could do:

byte count = 200;

void loop()
{
byte i;
......
for (i = 0; i < count; i++ )
{
// do the pin check or other process
}

// do the next thing, etc
}

which while that for-loop runs no other code can.

Or you could do:

byte count = 200;
byte i = 0;

void loop()
{
......
// do the pin check or other process for one value of i per loop()
if ( ++i == count) i = 0; // ++i adds 1 to i before the == is done

// do the next thing, etc
}

and now "the next thing" and rest of the code runs more often.

The for-loop manages your index but if you maintain the index yourself then loop() will become the wheel with access to all inside of it where the for loop closes all outside of itself.

Loop() is the always next step, the now that takes the sketch into the future next time around.
The best loop() code remembers the past (state), sees the present (non-blocking sensing and processing) and is ready for the future (state).

if you only need to run 30 seconds total, you can put a trap for that in loop() but I think that you will do more.

unsigned long trapAfter = 30000UL; // start time will be zero

void loop()
{
if ( millis() >= trapAfter ) // millis - start time of zero is millis
{
while ( 1 ); // this is a locked loop, sketch is stopped. You might turn the led off first.
}
.....

// rest of the code
}

Thanks for your answer GoForSmoke. However I have to run other code along with it.
Robin2, I can't understand the actual differenze that make this Work.
In The end, I need to Lock this in a while loop together with a couple other non blocking functions.
Can't I have a simpler example? The whole sketch is actually confusing to me.

Think about how you use the kitchen clock when you want to time the cooking of a chicken (and keep in mind that I am a very poor cook :slight_smile: ).

You don't sit in front of the cooker for 90 minutes - which is the equivalent of using WHILE.

Instead you check the time when you put the chicken in (that's the equivalent of making a note of the value of millis() and you figure out the time (say 6pm) when the chicken will be cooked.

Then you go about your business - cleaning the car, or hoovering or watching a game on TV.

Every so often you look at your watch (same as checking the value of millis() ) to check IF it is 6pm. That is the equivalent of if (millis() - startTime >= interval). In this case the interval is the equivalent of 90 minutes. Put together it looks like this

void loop()
  if (chickenNotInOven)  {
      putChickenInOven()
      startMillis = millis()
  }
  if (millis() - startMillis() >= interval) {
    takeChickenOut()
  }
}

Your case is a little more complicated because when you take the chicken out you want to start the timer again so you get a reminder when it is time to switch on TV for the next game

void loop()
  if (chickenNotInOven)  {
      putChickenInOven()
      startChickenMillis = millis()
  }
  if (millis() - startChickenMillis() >= interval) {
    takeChickenOut()
    gameTimerStart = millis();
  }
  if (millis() - gameTimerStart >= gameWaitMillis() {
    turnOnTV()
  }

}

Hope that helps. This is more a problem of understanding the concept than of understanding the code.

...R

Ok. It's a Little clearer Now.
However I still have doubts as to why my code never stops. I have even tried to use a variable called "enable" to reset At The end of the loop, but it isn't Working. Why that happens is something I need to understand.
An example with my code would be Lovely.

Mattia9914:
An example with my code would be Lovely.

Post your latest version with your best attempt to use millis() the way I have described and I will look at it.

...R

Ok, I finally made it.
Certainly not the best routine ever, and maybe the comments are a bit messy, but it works :smiley: .
The reason I can allow to use while is explained in the sketch.

#define left 4 //left
#define right 5 //right
#define ledPin 13// led pin to blink when while loop is over 

byte state = 0;
bool turnRight = false; //disables the motor from rotating right
const long work = 5000; //working time for the motor
const long pause = 3000; //pause time for the motor
bool done = false;

unsigned long currentTime = 0;//current time

void setup()
{
  pinMode(left, OUTPUT);
  pinMode(right, OUTPUT);
  pinMode(ledPin, OUTPUT);
}

void loop()
{

    unsigned long nowTime = millis();
    while (millis() - nowTime < 30000)//using this systema actually stops the cycle at the end when necessary
    {
      if(done==false)
      {
       onOff();
       //here I am going to add other functions such as fill() and heat() in order to achieve the wash phase of the washing machine
       //No big problem to use while, since I am separating each phase into sections and functions which are non-blocking (wash functions cosists of pre-heat, heating and after heating, 
       //they block each other out, but the functions in them don't. So, fill(), onOff() and heat are non blocking functions(). 
       //Obviously, I have already programmed the other two with millis() only and without any while loops or delays
      }
    }
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);//blinking the led to show the phase is over
    done=true;
    //delay(5000);
    //done=false; I added these to show that by putting done to false it actually starts over again, so it looks like I can use that variable for the tumbling phase when necessary and set it to true when not necessary
    
}






  void onOff()//the code here is as was before
  {
    if (state == 0)                           //if state equals 0
    {
      if (turnRight == false)                 //and rotations to the right are not enabled
      {
        digitalWrite(left, HIGH);           //rotate to the left
      }
      else
      {
        digitalWrite(right, HIGH);             //if rotations to the right are enabled, turn right
      }
      if (millis() - currentTime >= work)     //if the working time is already over
      {
        if (turnRight == false)                 //and we have to turn off the motor
        {
          digitalWrite(left, LOW);            //if it was turning to the left, turn off left
        }
        else
        {
          digitalWrite(right, LOW);              //else, turn off right
        }
        state = 1;                            //set state to 1
        currentTime = millis();                 //reset time
      }
    }
    else if (state == 1)                      //if state equals 1
    {
      if (millis() - currentTime >= pause)      //and pause time is already over
      {
        currentTime = millis();                 //reset timer
        state = 0;                            //set state to 0
        if (turnRight == false)                 //if the motor was previously turning to the right
        {
          turnRight = true;                     //enable turnRight to make it rotate to the right next time
        }
        else
        {
          turnRight = false;                    //if it was turning to the right, disable turnRight to make it rotate to the left
        }
      }
    }
  }

Let me know what you think and, obviously, thanks again.

Mattia9914:
Thanks for your answer GoForSmoke. However I have to run other code along with it.

Most of what I wrote is for letting many things run together.

But I look at your code and see not only millis timing but delay()s... you had me fooled, I thought that you understood millis timing.