Millis usage as timestamp reference?

Maybe the title is a bit off, but take a look at this bit of code:

// HOW DO I DO THIS PART...... I can make the reference point, but the code will be running through and changing that currentMillis variable so I never get a triggering...

// Make a time reference point when the motor started lowering the curtains
      unsigned long currentMillis = millis();
      
   if(currentMillis >= currentMillis + TimeMotorOn) {
   
       // Stop lowering the curtains
          digitalWrite(IN1,LOW);
          digitalWrite(IN2,LOW);
    
           if(curtainStatus == false) {
               curtainStatus = true;}
       
           else {
            
           curtainStatus = false;
         };

As you can see I need a timeStamp when the motor is turned on. When 10 seconds have passed I need the motor to stop. But atm. the currentMillis is being redefined everytime the code gets looped. This means that the condition stated in the if statement never will be triggered....

Any ideas how I can make this work?

I have been looking at the do..while command, but doesnt that put the rest of the sketch on hold just like a delay() would do?

Maybe look at how the blink without delay example handles this situation.

I have, it was the first thing I did, but I can't see how that sketch is doing what I need it to.

If I used the blinkwithoutdelay sketchs approach for my situation, the curtains would stop immediately after they were turned on, because the (currentMillis - previousMillis) would be a much larger number than the MotorOn interval of 10000 milliseconds.

Isnt that true or have I missed something?

have I missed something?

I think that is likely.
Perhaps it is something to do with where the variables are declared, but it is difficult to see when only snippets are posted.

Here is all the code, but atm. its a bit of a mess, because I try different stuff out..

// Pin connections defined.
int ENA=3; //Connect on Arduino, Pin 3
int IN1=4; //Connect on Arduino, Pin 4
int IN2=5; //Connect on Arduino, Pin 5
int ENB=6; //Connect on Arduino, Pin 6
int IN3=7; //Connect on Arduino, Pin 7
int IN4=8; //Connect on Arduino, Pin 8


// The time the motor will be on when either raising or lowering the curtains (here 10 seconds = 10000 millis).
unsigned long TimeMotorOn = 10000; 
long previousMillis = 0;

// A variable is created to hold the status of the curtains. true = curtains lowered, false = curtains raised.
curtainStatus = false;

void setup() {
 pinMode(ENA,OUTPUT);
 pinMode(ENB,OUTPUT);
 pinMode(IN1,OUTPUT);
 pinMode(IN2,OUTPUT);
 pinMode(IN3,OUTPUT);
 pinMode(IN4,OUTPUT);
 
 // Activate motor A and B
 digitalWrite(ENA,HIGH);
 digitalWrite(ENB,HIGH);
}


void loop(){
 /*
 The following is just notes for myself... Jump to HERE WE GO AGAIN..
 
 // Når motorA skal tændes sættes IN1 til HIGH og IN2 til LOW og motoren drejer en vej rundt. 
 digitalWrite(IN1,LOW);
 digitalWrite(IN2,HIGH);
 //Når motorA skal dreje den anden vej rundt sættes IN1 til LOW og IN2 til HIGH.
 digitalWrite(IN1,HIGH);
 digitalWrite(IN2,LOW); 
 //Når motorA skal slukkes sættes enten både IN1 og IN2 til LOW eller HIGH eller også slukker man ved at sætte ENA til LOW.
 
 // Det samme gælder motorB som bare bruger IN3 og IN4.
 
 //PWM, såfremt at motorerne har brug for at blive sænket i hastighed, så skal ENA og ENB sættes til pins på arduino boarded der understøtter PWM. PWM pins 3,5,6,9,10,11.
 // Følgende kode kan bruges til at sænke hastigheden på motorerne:
 analogWrite(ENA, (4/255)); //værdi mellem 0 og 255. Læg ud med at prøve med 1/4 hastighed
 */
 
 
 // HERE WE GO AGAIN:
 
 // Here we start controlling the curtains behavior:
 
 // If there is to much light and the temperature is 25 or higher and the curtains are not down, the following code will be executed..
 if(lightValue >= 300 && indetermometer >= 25 && curtainStatus == false) {
   
   // Set PWM speed - MAYBE I CAN MOVE THIS BIT TO THE TOP WHERE I DEFINE THE DIFFERENT VARIABLES?
      analogWrite(ENA, (4/255)); // 1/4 motor speed to begin with. Maybe it can go faster, but lets go slow..
   
   // Lower curtains
      digitalWrite(IN1,LOW);
      digitalWrite(IN2,HIGH);

// HOW DO I DO THIS PART...... I can make the reference point, but the code will be running through and changing that currentMillis variable so I never get a triggering...

// Make a time reference point when the motor started lowering the curtains
      unsigned long currentMillis = millis(); //f.eks. 60000
      
   if(currentMillis - previousMillis > TimeMotorOn) { // 60000-0>10000 = true
       previousMillis = currentMillis;
       
       //65000-60000 > 10000 = false
       
       
       // Stop lowering the curtains
          digitalWrite(IN1,LOW);
          digitalWrite(IN2,LOW);
    
           if(curtainStatus == false) {
               curtainStatus = true;}
       
           else {
            
           curtainStatus = false;
         };
         

  // If there is not much light and the temperature is below 25 and the curtains are down, the following code will be executed..
  if(lightValue < 300 && indetermometer < 25 && curtainStatus == true) {
   
   // Set PWM speed 
      analogWrite(ENA, (4/255));
   
   // Raise curtains
      digitalWrite(IN1,HIGH);
      digitalWrite(IN2,LOW);
 
   // Make a time reference point when the motor started raising the curtains
      unsigned long currentMillis = millis();
   
   if(currentMillis >= currentMillis + TimeMotorOn) {
   
       // Stop curtain motor
          digitalWrite(IN1,LOW);
          digitalWrite(IN2,LOW);
    
           if(curtainStatus == true) {
               curtainStatus = false;}
       
           else {
            
           curtainStatus = true;
         };
// A variable is created to hold the status of the curtains. true = curtains lowered, false = curtains raised.
curtainStatus = false;

It is a mess, it doesn't compile.

I know it doesnt compile.. It is a work in progress:d... I am new to this, so bear with me if you can.. The whole point of this is to keep away from the delay() function that stalls the other things I want the sketch to do.

I just need that motor to stop when 10 seconds has elapsed after starting the motor. If it doesnt stop it tears my greenhouse curtains apart. How would you do it with the millis? If you just took my useless code and threw it away. Scratch it all.. How would you do it? Any hints?

I get the impression that you want to have a function that will run a piece of code but only if has been 10 seconds since the reference time?

If so, I like to use this general pattern

unsigned long startTime;

unsigned char thingNeedsDoing;

//Setup variables to tell poll() that it needs to do a thing in ten seconds.
void doThingInTenSeconds()
{
//start motor here?
//set reference time
  startTime = millis();

  thingNeedsDoing=1;

}

//Check if it is time to do the thing, and if so do it. Call this in your main loop.
void poll()
{
  if(thingNeedsDoing)
  {
//check if it has been ten seconds
    if ((millis()-startTime) >10000)
    {
      //Do something here, like stopping the motor

      //It doesn't need doing, becuse we already did it
      thingNeedsDoing =0;

    }
  }

}

EDIT: fix millis() rollover bug in code

That looks exactly like the feature I was looking for. I will try to incorporate that into my code and see how it works out.

Thank you very much for your input.

Can this:

void dothingsinTenSeconds() function

be put into an if statement and placed in the void loop()?

It can be much simpler. Think of how you use a clock to determine when your chicken is cooked. You note the start time and how long it needs to cook for. Then periodically you see if the time has advanced to the stage where the full cook time has elapsed. The motorOn variable is the equivalent of knowing the chicken is in the oven so you don't waste your time checking an empty oven.

unsigned long previousMillis;
unsigned long currentMillis;
int motorRunMillis = 10000; 
boolean motorOn = false;

void setup() {
  // whatever is needed here
}

void loop() {
  currentMillis = millis();
  // whatever is needed
  motorRun();
}

void motorRun(){
    if (motorOn == false) {
       motorOn = true;
       previousMillis = currentMillis;
       // stuff to turn motor on
    else {  // i.e. if motorOn == true
       if (currentMillis - previousMillis >= motorRunMillis) {
           // stuff to turn motor off
           motorOn = false;
       }
    }
}

...R

Let me just run through this step by step so I understand it fully:

  1. In the main loop I make a if statement with conditions like temp higher than threshhold ect.
  2. When the condition is meet, the motorON() gets executed.
  3. An if statement now checks if the motorON variable is true or false.
  4. If it is false, it sets it to true (turns on the motor) and makes a timeStamp with the previousMillis = currentMillis;
  5. The loop runs again (and all the other stuff in the void loop() gets executed too.
  6. The if statement in the void loop() for the motorON() is still true and the motorON() gets executed one more time.
  7. The condition in the first if statement has now changed. The motorON variable is now true.
  8. Now the "else" statement gets executed and the (currentMillis - previousMillis >= motorRunMillis) gets checked.
  9. If that returns true (either now or in a later loop-run-through), the motorON variable is set to false and the motor stops.

Sounds just what I need if it is so.

That sounds right - with just one minor correction. Line 2 should be "... motorRun() gets executed" (not motorON).

You could replace the "// stuff to turn motor on" with code to turn on (or off) an LED just to try out the code.

...R

Yes of cause, thanks for correcting me.

What about this void motorRun(), is that just a way of structuring the code? I mean the motorRun() in the main loop could also just be substituded with all the code running in the void motorRun()? If so that is a very nice way of structuring code and I think I will use that from now on.

Its just a way of organizing the code.

I find it makes life much easier to have short functions with sensible names. It makes it much easier to follow the flow of the logic and it also means that each small piece is easy to understand and change (if necessary) without screwing up other parts.

Another advantage is that you can copy a small part into a short demo script to try it out on its own if you are having a problem.

And at the start of a program it can be useful just to write empty functions that represent the overall structure of the problem. Then you can fill them in bit by bit as you get other parts of the code working.

...R

The code in Reply #10 would turn the motor off when required, and then immediately turn the motor on again and restart the timing. It seems to me that the 'start motor and record the time it started' logic should only be performed once, perhaps in setup(), rather than in the 'check whether it is time to stop the motor' function.

I don't quiet follow. Can you please elaborate a bit more?

I can't define it in setup() because that is only run once. The system I am making does require that these codes can run more than runs if certain conditions are made.

PeterH:
The code in Reply #10 would turn the motor off when required, and then immediately turn the motor on again and restart the timing.

That's quite right. It needs another control variable, "motorRequired" like this. Note that this version won't run the motor as it is because there is nothing to change motorRequired to true. I presume the OP will figure out how to add that.

unsigned long previousMillis;
unsigned long currentMillis;
int motorRunMillis = 10000; 
boolean motorOn = false;
boolean motorRequired = false;

void setup() {
  // whatever is needed here
}

void loop() {
  currentMillis = millis();
  // whatever is needed
  motorRun();
}

void motorRun(){
  if (motorRequired == true) {
    if (motorOn == false) {
       motorOn = true;
       previousMillis = currentMillis;
       // stuff to turn motor on
    else {  // i.e. if motorOn == true
       if (currentMillis - previousMillis >= motorRunMillis) {
           // stuff to turn motor off
           motorOn = false;
           motorRequired = false;
       }
    }
  }
}

...R