Three time conditions using the "millis()" function

Hi,

I’m working on a temperature control project.

I have trouble to implement three time settings using the millis() function.
In the sketch, I put it in “delay() “ as a place holder for the millis() function I want to use.
Can somebody help me to adjust the sketch with the millis () function to replace all three delay functions.

Thank you!

Stefan

#include <Wire.h>
#include <DallasTemperature.h>
 
#define ONE_WIRE_BUS 7 
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

const int Motor1 = 8; 
const int Motor2 = 2;

unsigned long currentmillis = 0;
unsigned long previousmillis = 0;
long Interval_l = 5000;            //stands for delay 5000ms
long Interval_2 = 10000;           //stands for delay 10000ms
long Interval_3 = 50000;           //stands for delay 50000ms

void setup() {

pinMode(Motor1, OUTPUT);
pinMode(Motor2, OUTPUT);

    }

void loop() {

sensors.requestTemperatures();
float temperature = sensors.getTempCByIndex(0);
  
if(temperature < 23)                  
    {
   digitalWrite(Motor1,HIGH);        //If temperature < 23 turn on Motor1 on for 5000ms
   delay (5000);
   digitalWrite(Motor1,LOW);        //After 5000ms turn Motor1 off, wait 10000ms (Time starts after Motor 1 was turnded off)
   delay (10000);                   // Go through loops till line 52 becomes true
           }                         
                                    //Put this the right way :)
                                    //currentmillis = millis();
                                    //(currentmillis - previousmillis >= Interval_1);
                                    // previousmillis = currentmillis;

                                    //Interval_2;
                                    //Interval_3;
           
    else if(temperature > 26)
    {
    digitalWrite(Motor2,HIGH);     //If temperature > 26 turn Motor2 on for 5000ms
    delay (5000);            
    digitalWrite(Motor2,LOW);     //After 5000ms turn off Motor 2, wait 10000ms (Time starts after Motor 2 was turnded off)
    delay (10000);                // Go through loop till line 52 becomes true

if ((temperature > 23)&& (temperature < 26)){      // If the temperature is between 23C und 26C don't do anythimng just wait 50000ms
  delay (50000);                                   //  then check temperatures again.
}
}                 
}

What trouble did you have? Please post the code you had trouble with, and we will help you with it. Requests for complete code creation belong in the Gigs and Collaborations sub forum.

You will need different "previous millisecond" variables for each of the timed events.

See this tutorial, for example.

The demo Several Things at a Time illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

It looks like what you are trying to do is:

If the temperature is < 23 run Motor1 for 5 of every 15 seconds (5 on, 10 off).
If the temperature is > 26 run Motor2 for 5 of every 15 seconds (5 on, 10 off).

Is that what you want the sketch to do?

What if the temperature changes? For example, what if Motor1 is running and the temperature goes above 26? Do you want Motor2 to start or wait until Motor1 stops? Do you want Motor1 to stop?

  1. Who is using the I2C bus ?
  2. You forgot to press Ctrl+T.
  3. Do you like this: The Finite State Machine | Majenko Technologies ?

The Wire library for the I2C bus included with "#include <Wire.h>" but no one is using the I2C bus. You can remove that.

When you press Ctrl+T or make the text layout look better, then you see that there is something wrong with the '{' en '}'. The "if ((temperature > 23) && (temperature < 26))" does not work.

Using millis() requires a variable that is the index or the state to tell in which interval the sketch is. Then it is only a small step to use a Finite State Machine that uses millis(). It takes some time to get used to, but then everything can be split into small parts and you only have to make each small part (each state).

Since only one motor is on at a time, it is allowed to turn both off at the end of the 5 seconds and then wait 10 seconds. The 50 seconds waiting can also be squeezed into that. Perhaps a base interval of 5 seconds can be created to reduce the requesting of the temperature. That would be a 'quick and 'dirty' sketch. When doing it right, it does not get as nice as a Finite State Machine. I see no good solution between 'quick and dirty' and the Finite State Machine.

This is the 'quick and dirty' sketch:

// Quick and Dirty

#include <OneWire.h>
#include <DallasTemperature.h>

#define ONE_WIRE_BUS 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

const int Motor1Pin = 8;
const int Motor2Pin = 2;

unsigned long previousMillis;
int counter;                  // counts down within interval.
bool turnOff = false;         // tells if the motors need to be turned off

void setup()
{
  Serial.begin( 9600);
  Serial.println( "----------------------");
  Serial.println( "Temperature controller");
  Serial.println( "----------------------");
  pinMode(Motor1Pin, OUTPUT);
  pinMode(Motor2Pin, OUTPUT);
}


void loop()
{
  unsigned long currentMillis = millis();

  // This is a 5 second software timer with millis().
  // It is the base for all timing.
  
  if( currentMillis - previousMillis >= 5000)
  {
    previousMillis = currentMillis;


    // Always read temperatures each 5 seconds, whether it will be used or not
    sensors.requestTemperatures();
    float temperature = sensors.getTempCByIndex(0);

    Serial.print( "Temperature = ");
    Serial.println( temperature);

    if( temperature < -100.0)
    {
      // Something is wrong with the temperature sensor.
      // When it is not connected it will return -127.0 degrees.
      // Turn motors off ? Sound an alarm ? Wait until it is reconnected ?
      Serial.println( "Error, temperature sensor not found");
    }
    
    // This is the important part.
    // Here are the decisions made what to do and how to use the interval.
    // Action is taken at the end of each interval.

    if( counter == 0)                          // End of this interval ?
    {
      if( turnOff)                             // special case, a motor is on and should be turned off
      {
        Serial.println( "Turning off motors");
        digitalWrite(Motor1Pin, LOW);  // After 5000ms turn Motor1 off, wait 10000ms (Time starts after Motor 1 was turnded off)
        digitalWrite(Motor2Pin, LOW);  // After 5000ms turn off Motor 2, wait 10000ms (Time starts after Motor 2 was turnded off)
        counter = 2;                           // 2 * 5 = 10 seconds
        turnOff = false;
      }
      else
      {
        if( temperature < 23.0)
        {
          Serial.println( "Motor 1 on");
          digitalWrite(Motor1Pin, HIGH);       // If temperature < 23 turn on Motor1 on for 5000ms
          counter = 1;                         // 1 * 5 = 5 seconds
          turnOff = true;
        }
        else if (temperature > 26.0)
        {
          Serial.println( "Motor 2 on");
          digitalWrite(Motor2Pin, HIGH);       // If temperature > 26 turn Motor2 on for 5000ms
          counter = 1;
          turnOff = true;    
        }
        else
        {
          // If the temperature is between 23C and 26C don't do anythimng just wait 50000ms
          Serial.println( "Wait 50 seconds");
          counter = 10;                        // 10 * 5 = 50 seconds
        }
      }
    }

    counter--;
  }
}

The 'counter' keeps track of how long a interval is and the 'turnOff' is an exception to turn off the motors. However, turning off the motors should be a normal part and not an exception. A good sketch is open and well split into functional parts.

When you don't understand this sketch, then you should not use it and you should not try to understand it. Invest your time in learning the Finite State Machine.

For others: Yes, I know I should not show such a sketch and yes it hurts to the eyes to see it.

Hi all,

thank you for the great support.

@ aarg
This was the code I was experimenting, with not much success.

currentmillis = millis();
  
if(temperature < 23)                  
    {
   digitalWrite(Motor1,HIGH);                                 
   if (currentmillis - previousmillis >= Interval_1)
   digitalWrite(Motor1,LOW);
   previousmillis = currentmillis; 
    if (currentmillis - previousmillis >= Interval_2)     
   previousmillis = currentmillis;                                       
           }                         
                                           
    else if(temperature > 26)
    {
    digitalWrite(Motor2,HIGH);     
    if (currentmillis - previousmillis >= Interval_1)         
    digitalWrite(Motor2,LOW); 
     previousmillis = currentmillis; 
    if (currentmillis - previousmillis >= Interval_2)                 
 

if ((temperature > 23)&& (temperature < 26)){     
   if (currentmillis - previousmillis >= Interval_3)                               
}      previousmillis = currentmillis;              
}

@johnwasser

It looks like what you are trying to do is:

If the temperature is < 23 run Motor1 for 5 of every 15 seconds (5 on, 10 off).
If the temperature is > 26 run Motor2 for 5 of every 15 seconds (5 on, 10 off).

yes that's correct (the interval could also be different, like 2 on 7 off)

What if the temperature changes? For example, what if Motor1 is running and the temperature goes above 26? Do you want Motor2 to start or wait until Motor1 stops? Do you want Motor1 to stop?

It is a good questions, I haven't though that far.
The best would be if motor 1 stops immediately after the temperature goes above 26

@Robin2
@jremington

These are very good background information, it helps to understand that topic way better.

@Koepel

This is a very interesting approach to solve that topic.
The sketch may don't like nice in your eyes.
But at my stage of programming I'm very happy if a sketch does what it should.
Thank you for modifying the sketch!!!

When delay() is "replaced" by millis(), that means that the sketch has to be rewritten.

It takes some time for everyone to put the delay() away. You wanted to use millis() in the same way as delay(). That is not possible. You have to rewrite the sketch.
The Blink Without Delay is really important.
https://www.arduino.cc/en/tutorial/BlinkWithoutDelay.

Then read the explanations in the link that Robin2 gave.
Some of us have a certain style of writing code, but in the end the millis() is used in the same way. There are only a few options to do it right.

To make a sketch with millis() run smooth, let the loop() run as fast and as often as possible.
Using millis() is checking if it is time to do something.
That means that most of the time the code in the loop() is not doing much, only checking if it is time.
When a interval has finished then you can do something (turn a motor on or a led off), and immediate return to the situation that the loop() runs fast and often without doing much.

Thank you Koepel for your support!