Having trouble with millis()

I am having trouble getting millis() to co-operate... I am new to arduino but have worked through the basic blinking lights and such... I am having trouble with the following:

boolean stageTempReached = false; //has the temp been reached for this stage, starts out as no boolean timer = false; //is the timer running because the temp has been reached? byte Stage = 1;

void setup() { Serial.begin(9600); //start serial communications for test purposes

}

void loop() { clockCheck (10); delay (1000); }

void clockCheck (int minHold) //Subroutine that checks time since the correct temp was reached //and changes to the next stage if needed { unsigned long timeStart;

if ((stageTempReached == true) && (timer == false)) {(timeStart = millis()); (timer = true);}

//if (millis() >= (timeStart + (minHold * 60000))) {(Stage = (Stage + 1)); //(timer = false); //(stageTempReached = false);} Serial.println(timeStart); Serial.println(millis());

}

when the serial.prints come out, they don't match. The first will be like 513954200 and the second will actually be the number of milliseconds since program start. If I comment out the first if statement, things work out great. What is it about my if statement that makes my arduino make up giant numbers?

Thanks for any help

timeStart needs to be a global to persist from run to run of clockCheck. It is currently declared inside clockCheck, so it’s local to clockCheck (and therefore contains uninitialized garbage sometimes).

Move the declaration of timeStart above the start of the clockCheck function to make it global and see if that helps with your problem.

-br

and init it to 0!

Mark

Tried both options with and without setting to 0 in global, now it reads 0 each time on the first serial.print and the correct milliseconds for the second number

Would you post the updated code, and include it inside code tags?

The little "#" button above the smilies above the edit window will add code tags for you.

-br

What are you attempting to do? What are you expecting it to do? And yeah, please use code tags.

thanks for any help.

boolean stageTempReached = false; //has the temp been reached for this stage, starts out as no
boolean timer = false;  //is the timer running because the temp has been reached?
byte Stage = 1;
unsigned long timeStart = 0;
void setup() {
 Serial.begin(9600); //start serial communications for test purposes

}

void loop() {
clockCheck (10);
delay (1000);
} 
  
  void clockCheck (int minHold)  //Subroutine that checks time since the correct temp was reached
                               //and changes to the next stage if needed
{
      
             
                  if ((stageTempReached == true) && (timer == false)) {(timeStart = millis());
                                                                       (timer = true);}
                 
                        //if (millis() >= (timeStart + (minHold * 60000))) {(Stage = (Stage + 1));
                                                       //(timer = false);
                                                       //(stageTempReached = false);}
          Serial.println(timeStart);
          Serial.println(millis());   
  
}

I was looking for that code button. I want that first if statement to start a timer, once the timer is up it changes the stage to stage+1, which, in the rest of the program that I did not include, will do different things.

So when I edit your code down to the readable minimum, this is what I get:

boolean stageTempReached = false; //has the temp been reached for this stage, starts out as no
boolean timer = false;  //is the timer running because the temp has been reached?
byte Stage = 1;
unsigned long timeStart;

void setup() {
    Serial.begin(9600);
}

void loop() {
    clockCheck (10);
    delay (1000);
} 
  
//Subroutine that checks time since the correct temp was reached
//and changes to the next stage if needed
void clockCheck (int minHold) {
    if (stageTempReached && !timer) {
        timeStart = millis();
        timer = true;
    }
    Serial.println(timeStart);
    Serial.println(millis());
}

Since nothing ever changes stageTempReached, what are you expecting?…

-br

stageTempReached is a boolean value passed to the sub routine. It get reset elsewhere... I did not want to paste in 200 lices of code so I just re-produced my problem... I am programing the Arduino to control a crockpot to make yogurt. It happens in three stages. 1 - heat to 185 and hold for 10 minutes, 2- cool to 110 and hold for 10 minutes... sound buzzer to add started, pressa button to go to stage 3, 3 - keep at 100 for 8 hours.

My program has an if statement to check the stage, then passes temp ranges to a sub routine that turns a relay on or off based on current temp. Then the program checks the clock.. that is this function

once the temp is reached (stageTempReached returns true, and the variable timer is off) it turns on the timer to wait for the 10 minutes while still checking with the relay. after 10 minutes the stage increases by one and the if statement now runs stage 2 numbers. The problem is I can't get the timer to maintain the correct time... I get crazy values like 123452000 for milliseconds... it works great if I remove: if ((stageTempReached == true) && (Timer = false)) but I need them to start the hold time when I want them too.

I'm afraid it is not possible to provide good help without seeing all your code.

-br

Ok, I took your code and reindented it and renamed a variable because I found it very difficult to read.

//----------------------------------------------------------------
// I added this because I hate using the Serial.print() functions
//----------------------------------------------------------------
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
static char const endl = '\n';

//----------------------------------------------------------------
// I set this to true to simulate that the temp has been reached.
//----------------------------------------------------------------
boolean stageTempReached = true; //has the temp been reached for this stage, starts out as no
//----------------------------------------------------------------
// I renamed this varialbe to make more sence while reading the code.
//----------------------------------------------------------------
boolean timerRunningDueToTempReached = false;  //is the timer running because the temp has been reached?
byte Stage = 1;
unsigned long timeStart = 0;
void setup()
{
  Serial.begin(9600); //start serial communications for test purposes
}

void loop() {
  //----------------------------------------------------------------
  // Changed this from 10 to 1 just to see this occur faster
  //----------------------------------------------------------------
  clockCheck (1);
  delay (10000);
} 
  
void clockCheck (int minHold)  //Subroutine that checks time since the correct temp was reached
                               //and changes to the next stage if needed
{
      
             
  //----------------------------------------------------------------
  // I removed the "== true" and "== false" and used natural
  // language paradigms to make this more readable.
  //----------------------------------------------------------------
  if (stageTempReached && !timerRunningDueToTempReached) {
    timeStart = millis();
    timerRunningDueToTempReached = true;
    // added this to report that this has occured.
    Serial << "timerRunningDueToTempReached = true" << endl;
  }
 
  //----------------------------------------------------------------
  // I uncommented this to see what it would do
  //----------------------------------------------------------------
  if (millis() >= (timeStart + (minHold * 60000))) {
    Stage = (Stage + 1);
    timerRunningDueToTempReached = false;
    stageTempReached = false;
    // added this to report the stage level.
    Serial << "Stage: " << Stage << endl;
  }
  Serial << timeStart << " -- " << millis() << endl;
}

Now, I’ve not actually changed your code’s flow. It runs the same except that it triggers 1 min after start of execution instead of 10 min after stageTempReached is set to true. However, (at least) I find it easier to read, and may be easier to debug.

Now tell me, is this doing what you intended? If not, what did you expect to happen?

Thanks… but It didn’t work. I’m new to this so I’m not sure the following is.

template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
static char const endl = '\n';

All I know at this point is Serial print. I understand the time change, I’ve dove that too as a test. And I didn’t know there was an alternative to ==true and false. I assume that if I don’t put a value, it checks for true and if I put a ! in front it checks for false???

Anyway, I will post my entire code here as asked. I am having trouble with the millis() function in the checkClock() sub-routine. I have never made an entire program before; this represents my efforts other then following along in books and making adjustments to per-existing programs. I would love to hear your comments, but please, be gentile.

//Jeff's atempt at Programming a Arduino to Control the Temperature
// of a Crock-pot to make yogurt

//Making yogurt happens in three stages
//Stage 1 - Heat up milk to 185 degrees and hold for 10 minutes
//Stage 2 - Cool to 110 degrees and hold for 10 Minutes - Add starter
//Stage 3 - Hold temp at 100 for eight hours (480 minutes)

byte Stage = 1;
int relayPin = 9;  //defines signal pin for relay hhoked up to the crock pot
int tempPin = A0;  //defines signal pin for thermistor
int buttonPin =10; // defines pin for the button
int buzzerPin = 11; //defines pin for buzzer
int highTemp;      //used to pass info to maintainTemp function
int lowTemp;      //used to pass info to maintainTemp function
int minHold;      //used to pass info to maintainTemp function
int desiredTemp;  //used to set the desired temp for the stage
boolean stageTempReached = false; //has the temp been reached for this stage, starts out as no
boolean timer = false;  //is the timer running because the temp has been reached?
boolean alert = false; //has the alert between stages 2 and 3 been handled?
long timeStart = 0;
void setup()               
{ 
  pinMode(relayPin, OUTPUT); //relayPin as output
  pinMode(tempPin, INPUT);   //tempPin as input
  pinMode(buttonPin, INPUT); //buttonPin as input
  //digitalWrite (buttonPin, LOW); //turn on pull-down resister for button
  pinMode(buzzerPin, OUTPUT); //buzzer pin as output
  Serial.begin(9600); //start serial communications for test purposes
  analogReference(EXTERNAL); //refernces my voltage divider circut to 3.3v (wire from 3.3 to AREF) less noise
}

void loop() {
  
 // STAGE 1 - Warm Up 
 if (Stage == 1)
   {desiredTemp = 85;
   stageTempReached = maintainTemp ((desiredTemp+2), (desiredTemp-2));
   clockCheck (1);
   delay (1000); 
   } 
 //STAGE 2 - Cool Down
  if (Stage == 2)
   {desiredTemp = 80;
   stageTempReached = maintainTemp ((desiredTemp+2), (desiredTemp-2));
   clockCheck (.1); 
   //if ((Stage == 3) && (alert == false)) 
   //{while (buttonPin ==LOW)  //run buzzer until button is pressed
   //{tone(11, 622, 300);
  //delay(300);}
   //}
   //alert=true;
   delay (1000); 
   }
 //STAGE 3 Incubate
  if (Stage == 3)
   {desiredTemp = 75;
   stageTempReached = maintainTemp ((desiredTemp+2), (desiredTemp-2));
   clockCheck (1);
   delay (1000);   
   }  
 if (Stage == 4) {digitalWrite (relayPin, LOW);}  //Turn everything off

// This is test code to make sure getTemp() is working
float FTemp= getTemp();
Serial.print ("Temp. ");
Serial.print(FTemp);
Serial.println (" F");
Serial.print ("Stage ");
Serial.println (Stage);
Serial.print ("StageTempReached ");
Serial.println (stageTempReached);
Serial.print ("Hold Timer ");
Serial.println (timer); 
Serial.print ("Alert ");
Serial.println (alert); 
Serial.println ("");
}
     float getTemp() //Subroutine to get a temp in F from the temp sensor, for use in other functions
                  {
                    //CODE FROM HERE TO END OF BLOCK is stolen from the Internet, I don't understand it, takes average of 5 temps and converts to C
                                        int samples[5];  
                                        uint8_t i;               
                                          float average;
                                           // take N samples in a row, with a slight delay
                                          for (i=0; i< 5; i++) {
                                           samples[i] = analogRead(tempPin);
                                           delay(10);
                                          }
                                           // average all the samples out
                                          average = 0;
                                          for (i=0; i< 5; i++) {
                                             average += samples[i];
                                          }
                                          average /= 5;
                                          // Serial.print("Average analog reading "); 
                                          //Serial.println(average);       
                                          // convert the value to resistance
                                          average = 1023 / average - 1;
                                          average = 10000 / average;                         
                                          float steinhart;
                                          steinhart = average / 10000;     // (R/Ro)
                                          steinhart = log(steinhart);                  // ln(R/Ro)
                                          steinhart /= 3950;                   // 1/B * ln(R/Ro)
                                          steinhart += 1.0 / (25 + 273.15); // + (1/To)
                                          steinhart = 1.0 / steinhart;                 // Invert
                                          steinhart -= 273.15;                        // convert to C       
                                       
                      float FTemp;  //  My code again, translates to F                   
                      FTemp = (steinhart*9/5+32);
                      return FTemp;
                    }
   
     boolean maintainTemp (int highTemp, int lowTemp) //Subroutine to check temp against assinged values and determine power to relayPin
              {                             
                float FTemp = getTemp();  
                boolean tempMaintaining;
                
                if (FTemp <= lowTemp) {digitalWrite (relayPin, HIGH);}
                  //If current temp is less then the stages's low temp, turn it on
                if (FTemp >= highTemp) {digitalWrite (relayPin, LOW);}               
                  //If current temp is more then the stages's high temp, turn it off 
                 if ((FTemp < highTemp) && (FTemp > lowTemp)) {(tempMaintaining = true);}
                 else {(tempMaintaining = false);}
                
                return tempMaintaining; 
} 

void clockCheck (int minHold)  //Subroutine that checks time since the correct temp was reached
                               //and changes to the next stage if needed

{
       //unsigned long timeStart;
              
                  if 
                   ((stageTempReached == true) 
                   && 
                   (timer == false))
                                          {timeStart = millis();
                                          (timer = true);}
                                         // else {(timeStart = 0);}
                  
                        if (millis() >= (timeStart + (minHold * 60000))) {(Stage = (Stage + 1));
                                                       (timer = false);
                                                       (stageTempReached = false);}
          Serial.println(timeStart);
          Serial.println(millis()); 
}

You don't need to (and please do not) put assignments and function arguments in parenthesis. It makes your code harder to read:

        (Stage = (Stage + 1)); // too many ()
        Stage = Stage + 1;     // better
                Stage++;                   // best

This construct will have problems because minHold is declared int and 60000 is too big for an int constant:

    if (millis() >= (timeStart + (minHold * 60000))) {
        (Stage = (Stage + 1));
        (timer = false);
        (stageTempReached = false);
    }

Not sure it's your bug, but it's a problem. Something more like this might look like it would work:

    if (millis() >= (timeStart + ((unsighed long) minHold * 60000UL))) {
        (Stage = (Stage + 1));
        (timer = false);
        (stageTempReached = false);
    }

…but it will fail in 49 days when millis() rolls over. So you are better off using subtraction, something like this:

    if ((millis() - timeStart) > ((unsigned long) minHold * 60000UL))

-br

Edit: fixed typo.

MightyFinn:
Thanks… but It didn’t work.

Since I didn’t change what the actual code did, I didn’t expect it to. I did ask though, what did you expect it to output, but at the moment you probably didn’t know since you didn’t understand what I was doing with syntax you didn’t understand. I’ll explain as you ask questions:

MightyFinn:
I’m new to this so I’m not sure the following is.

template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

static char const endl = ‘\n’;



All I know at this point is Serial print.

Sorry, this is just syntactic sugar. It just allows for commands to be chained without the need to constantly type Serial.print(someVariableOrConstant); all the time. I.e. This:

char * name = "MightyFinn";
int hour = 4;
Serial.print("Hello ");
Serial.print(name);
Serial.print(".  It is now ");
Serial.print(hour);
Serial.println(" o'clock.");

becomes this:

char * name = "MightyFinn";
int hour = 4;
Serial << "Hello " << name << ".  It is now " << hour << " o'clock." << endl;

Which I find easier to read and less to type. It actually doesn’t change much in terms of the compiled code. Almost nothing except for the endl. This type of coding is done in the ostream class, and I just migrated it over to be compatible with the Print class (taken from here: http://playground.arduino.cc/Main/StreamingOutput). At this point, you don’t need to understand the template code, just understand that it works as advertised as it is a common C++ idiom.

MightyFinn:
And I didn’t know there was an alternative to ==true and false. I assume that if I don’t put a value, it checks for true and if I put a ! in front it checks for false???

Yes, ! in front of a Boolean means not. Numbers can also be used in place of Booleans, in which case 0 is interpreted as false, and !0 (not 0 or anything else other than 0) is interpreted as true. An if statement takes as an argument something that looks like a Boolean. The logical operators && and || take anything that looks like a Boolean as well.

MightyFinn:
Anyway, I will post my entire code here as asked. I am having trouble with the millis() function in the checkClock() sub-routine. I have never made an entire program before; this represents my efforts other then following along in books and making adjustments to per-existing programs. I would love to hear your comments, but please, be gentile.

lol, sure. However, I need you to go back to what I posted and tell me what you are expecting it to do. I could guess, but that would waste both of our time.

:) :) :)Woo-Hoo... I followed those suggestions, and changed a few things. Had to add another statement and it worked. A little more fiddling and I even got it to work correctly. Thanks guys. It's nice to know that there is a community out there that is so supportive of a guy who has no real background in this, and is willing to help me even if I don't yet know what a template is... I learned a lot. Thanks all.

MightyFinn: :) :) :)Woo-Hoo... I followed those suggestions, and changed a few things. Had to add another statement and it worked. A little more fiddling and I even got it to work correctly. Thanks guys. It's nice to know that there is a community out there that is so supportive of a guy who has no real background in this, and is willing to help me even if I don't yet know what a template is... I learned a lot. Thanks all.

Glad to help MF. :) Good luck!

I'd avoid accessing millis() twice in the same function.

If you want to get the current value, and do a comparison with it, and then assign it to a value, then what I would do is get the value from the function, and compare it, and assign it, without actually calling the function twice.