On-Off Timer

What you make of this way? This compiles but I don’t have the hardware to test, it may need fixing.

Please, spend some time to run and read and ask good questions, this is to help set you onto the easier track. You seem close already but maybe need more learning about the millis clock which is like a round clock with more than 12 hours but works the same.

I added a serial-echo task in the loop(). It should always work with no wait.
Important part: nothing in this code waits more than about 100 microseconds to run, closer to 20. Keep it this way and all will run smooth and fast.

#define leftTurnPin 4 //left  --- I used find&replace to make longer names easily
#define rightTurnPin 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

// all timing should be done with unsigned integer variables, ask why?

const unsigned long work = 5000; //working time for the motor
const unsigned long pause = 3000; //pause time for the motor

const unsigned long onOffRun = 30000; 
const unsigned long totalRun = 31000; 

bool done = false;

unsigned long currentTime = 0;//current time

void setup()
{
  Serial.begin( 115200 );

  pinMode(leftTurnPin, OUTPUT);
  pinMode(rightTurnPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
}

void loop()
{

  unsigned long nowTime = millis();

  if (millis() - nowTime < onOffRun)//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
    }
  }
  else  // must be..  millis() - nowTime >= onOffRun
  {
    if (millis() - nowTime >= totalRun)
    {
      digitalWrite(ledPin, LOW);
    }
    else if ( done == false )
    {
      done = true;
      digitalWrite(ledPin, LOW);
    }
  }
  
  if ( Serial.available())  // to show that you can interact ANY time if you No Block
  {
    Serial.write( Serial.read());  // echo input back to serial monitor
  }

  // put other new task here, inside of loop() to run with the others
}



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(leftTurnPin, HIGH);           //rotate to the left
    }
    else
    {
      digitalWrite(rightTurnPin, 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(leftTurnPin, LOW);            //if it was turning to the left, turn off left
      }
      else
      {
        digitalWrite(rightTurnPin, 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
      }
    }
  }
}

Change this

    while (millis() - nowTime < 30000)

to

    if (millis() - nowTime < 30000)

and allow loop() to do the repetition

And I can’t get a sense of what the function onOff() is trying to achieve. What does the variable state represent? Why are there variables called turnRight and turnLeft

I get the feeling that if I understood what you want it would all be done in 6 or 8 lines of code.

…R

I’m sorry, I didn’t notice that I still hadn’t told you what this is all about.
My goal is to create a Washing Machine Controller using Arduino. Since many cycles have common parts (such as fill(),heat(), onOff()) I decided to break them down into smaller pieces I could then copy and “enable” when necessary.

The onOff() function is nothing more than tumble(). I need it to reverse the motor direction, that’s why I have a variable called “turnRight”. That function is obviously not perfect, but it works.
Also, the only reason I used a delay and a led blinking is to inform me when the loop was over. The actual “wash code” will look something like this:

void loop()
{
  selectProgram(setProgram, setTemperature);
  lockDoor();

  bool cycleStarted = true;

  while (cycleStarted == true)
  {

    if (digitalRead(doorLock) == HIGH)
    {
      switch (setProgram) {
        case "Cottons":
          unsigned long nowTime = millis();
          while (millis() - nowTime < 30000)//using this system actually stops the cycle at the end when necessary
          {
            if (done == false)
            {
              fill();
              onOff();
              heat();
            }
          }
          done = true;
          //now I am 30 seconds into the cycle
          //Let's say I want to drain the water
          nowTime = millis();
          done = false; //used to say I want the machine to tumble
          while (millis() - nowTime < 10000)
          {
            onOff();
            drain();
          }
          //code for the rest of the cycle



        //here I'll have the final piece of code for the cycle
        cycleStarted=false;//avoids looping all over again
      }

    }
  }

}

Here I am making use of boolean type variables to stop the cycle: in real life, after the spin cycle, the machine does not start all over again by itself. I won’t be using any delay() in other parts of the code, except while waiting for the servo to get into position (I am using it to select which one of the detergent drawer tray should be filled with water).

I apologise again and I hope I didn’t make a mess with all of this.

My goal is to create a Washing Machine Controller using Arduino. Since many cycles have common parts (such as fill(),heat(), onOff()) I decided to break them down into smaller pieces I could then copy and “enable” when necessary.

You have that exactly right.

The switch-case statement will make coding states/modes easier.

I have a version that uses an “enabled” timer so that each step/case can end by setting the timer and switch to the next state so that runs after the wait is up but does not block during the wait.

void mySteps( void )  // this function should be called from inside loop()
{
  static byte myState = 0;                   // static variables are private to the function and keep their values 
  static unsigned long timeStart = 0;    // without the 'static' the values are lost when the function is done.
  static unsigned long timeWait = 0;    //  it is still a good idea to keep the names unique

  if ( timeWait > 0 ) // wait time of zero disables the timer
  {
    if ( millis() - timeStart < timeWait )
    {
      return; // no-block wait, next code runs immediately
    }
    timeWait = 0;
  }

  switch ( myState )
  {
    case 0 :
    // code to turn a led on
    timeStart = millis();
    timeWait = 500;
    state = 1;
    break;                  // if the break is left out, the next case code will also run

    case 1 :
    // code to make a servo move left
    state = 2;
    break;

    case 2 :
    // code to turn a led off
    timeStart = millis();
    timeWait = 1000;
    state = 3;
    break;

    case 3 :
    // code to make a servo move right
    state = 0;
    break;

    default:
    Serial.println( F( "** this line should never be reached" ));
    state = 0;
  }
}

void loop()
{
  mySteps();

  // other tasks go here
}

Great! So I could also use that code with state to tumble?

Yes. Another word for state might be mode.

The cases in that example always end with state changing. It doesn't have to. If you have a state that should repeat (like reading serial characters until end of word or line) then only change state when it is done or hits an error.

We use the word state for "process state" or "the state of the process", the technique name is Finite State Machine if you want to look up and read more. FSM's can be dead simple to very, very complex and often one FSM is contained within another, the modes having modes of their own. Wait until you are processing text if you think not.

Ok. Well, now I can finally try out my code then.

Mattia9914: My goal is to create a Washing Machine Controller using Arduino. Since many cycles have common parts (such as fill(),,heat(), onOff())

If I had known earlier what you are doing I would have recommended looking at Planning and Implementing a Program

I think you are starting at the wrong end by focusing on the timing.

A good way to develop a program is to create all the functions you need but leave them empty. That allows you to get the logic of the system figured out. Then you can fill out the code in the functions step by step.

For example

void loop() {
   if (drumFilled == false) {
      fill();
   }
   if (readyToWash == true) {
       wash();
   }
   if (washDone == true) {
       spin();
   }
}

void fill() {
   // do stuff
   readyToWash = true;
}

void wash() {
   // do stuff
   washDone = true;
}

void spin() {
   // etc etc
}

...R

Mattia9914: Ok. Well, now I can finally try out my code then.

I hope more that you are seeing the simple idea behind placing multiple codes in loop() to run as separate tasks without any holding the rest up.

I write code that I want to know how good is it? I add a task in loop() that adds 1 to a variable every time loop() runs and when 1 seconds goes by it prints that number and zeros the variable. Typical for light examples I get around 56K passes through loop() per second. I can live with 10K but the faster the better. That number tells me how much more I can set the machine to do.

Another task to add if led 13 is unused is a blinking status light. If the light blinks steady you know that loop() is averaging steady too.

I hope more that you are seeing the simple idea behind placing multiple codes in loop() to run as separate tasks without any holding the rest up.

I'm sorry but I can't undestand what you mean by that. Do you use it to check how busy the CPU is or?

Mattia9914:

I hope more that you are seeing the simple idea behind placing multiple codes in loop() to run as separate tasks without any holding the rest up.

I'm sorry but I can't undestand what you mean by that. Do you use it to check how busy the CPU is or?

I do it to be able to debounce my buttons and blink my leds and process serial input while generating serial output all at the same time and still have margin to do 20 more things if none of them hogs CPU cycles.

In my signature space at the bottom of my posts are 3 addresses to Nick Gammon blogs. The first covers the basic of this. Here is some of it, I highlighted the most important parts but you need to read what comes before.

Let's look at an analogy. Say you want to cook breakfast. You need to cook:

Coffee - takes 1 minute Bacon - takes 2 minutes Eggs - takes 3 minutes

Now a seasoned cook would NOT do this:

Put coffee on. Stare at watch until 1 minute has elapsed. Pour coffee. Cook bacon. Stare at watch until 2 minutes have elapsed. Serve bacon. Fry eggs. Stare at watch until 3 minutes have elapsed. Serve eggs.

The flaw in this is that whichever way you do it, something is going to be cooked too early (and get cold).

In computer terminology this is blocking. That is, you don't do anything else until the one task at hand is over.

What you are likely to do is this:

Start frying eggs. Look at watch and note the time. Glance at watch from time to time. When one minute is up then ... Start cooking bacon. Look at watch and note the time. Glance at watch from time to time. When another minute is up then ... Put coffee on. Look at watch and note the time. When 3 minutes are up, everything is cooked. Serve it all up.

In computer terminology this is non-blocking. That is, keep doing other things while you wait for time to be up.

Example code that runs blazing fast is code that can have MUCH added to it and still run smooth. Operative word here is "can". If you mix blocky code in, the word is then "can't".

Thanks for the explanation. However, I onyl need the functions to be non-blocking, inside the switch cases I need to have them blocked with while().

Mattia9914: Thanks for the explanation. However, I onyl need the functions to be non-blocking, inside the switch cases I need to have them blocked with while().

You shouldn't have any loop inside of loop() except Very Short Ones and fact is that you shouldn't need any.

It is a matter of arranging the logic to Everything has a chance to run every time that loop() runs because Everything includes external events and even you may find yourself wanting an Emergency Stop Button that can't be disabled by some task hogging the CPU. Good automation is always ready to respond immediately.

But go ahead, suit your short goal.

Mattia9914: I onyl need the functions to be non-blocking, inside the switch cases I need to have them blocked with while().

Sorry, but that is not a realistic approach and I think you will continually find yourself getting tripped up by things getting far more complex than they need to be.

Design the whole program to be non-blocking - as in Planning and Implementing a Program

...R

Ok. Thanks for the advice But I can’t undestand how that works. I use whiles because I need to freeze the program. If I only used if(), then for every iteration I’d have currentTime=millis() and it wouldn’t work.

Mattia9914: If I only used if(), then for every iteration I'd have currentTime=millis() and it wouldn't work.

True, you'd need to move where that's set and make nowTime into a global variable.

Sigh, since there's no way to do that you are well and truly stuck.

But if you want help then just sing out.

Thank you again. Maybe in the future I'll lay it out using states and perfecting everything, but for now it's just proof of concept ;-).

GoForSmoke: Sigh, since there's no way to do that you are well and truly stuck.

I presume that was not meant to be taken seriously, though I suspect it has been.

...R

Robin2: I presume that was not meant to be taken seriously, though I suspect it has been.

...R

How it was taken is a matter of the OP's process state. :)

I misunderstood then. But really, how can I use states and freze time?