this millis() business is driving me nuts

Folks,

Newbie with new project. Kinda stumped at the moment. The project is to turn on a circulation pump with the temperature falls below a certain level. To prevent short cycling when the temperature is hovering around the threshold temperature (the temp I want to turn on the motor)

I was planning on using a delay function. So essentially, when the temp reaches the threshold temp, the pump will come on and stay on for a predetermined amount of time, maybe ½ hour. Hopefully, in this way, I will prevent any potentially harmful, and annoying, short motor starts and stops.

The more I thought about the project, it would be nice to put an LCD screen on it so that I can see the threshold temp and the current temp displayed. I can work displaying the information, but I thought that I might like to see the current temp even while the motor is running, and the Nano is locked out due to the delay function. For this I think I need to use the millis() function, correct? Is what I want to accomplish even possible?

Yesterday I spent hours trying to figure it out but didn’t get far. I can see how the Blink Without Delay sketch works but incorporating it into a few lines that also checks to see if the temp exceeds the threshold temp has been troubling.

Below is my code, any help would be appreciated.

Best,

Tony

#include "DHT_U.h"
#define Type DHT11
int sensePin=7;
DHT DHTT(sensePin, Type);
float humidity;
float tempC;
float tempF;
int wait = 500;
float thresholdTemp = 79;
int redLed = 9;
int greenLed = 11;
unsigned long previousMillis = 0;
unsigned long interval = 10000;
int redLedState = LOW;


void setup() {
Serial.begin(9600);
DHTT.begin();
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
}


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

humidity = DHTT.readHumidity();
tempC=DHTT.readTemperature();
tempF=DHTT.readTemperature(true);

if (tempF < thresholdTemp) {
  digitalWrite(greenLed, HIGH);
  digitalWrite(redLed, LOW);
  previousMillis = currentMillis;
}

else if (currentMillis - previousMillis < interval) {
  digitalWrite(redLed, HIGH);
  digitalWrite(greenLed, LOW);
}

  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print(".   TempC: ");
  Serial.print(tempC);
  Serial.print(".   TempF: ");
  Serial.print(tempF);
  Serial.println(". ");

delay (wait);
}

You've pretty much got it. Try this:

void loop()
{
  unsigned long currentMillis = millis();
  humidity = DHTT.readHumidity();
  tempC = DHTT.readTemperature();
  tempF = DHTT.readTemperature(true);
  if (tempF < thresholdTemp)
  {
    digitalWrite(greenLed, HIGH);
    digitalWrite(redLed, LOW);
    previousMillis = currentMillis;
  }
  if ((currentMillis - previousMillis > interval) && (tempF >= thresholdTemp))
  {
    digitalWrite(redLed, HIGH);
    digitalWrite(greenLed, LOW);
  }
  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print(".   TempC: ");
  Serial.print(tempC);
  Serial.print(".   TempF: ");
  Serial.print(tempF);
  Serial.println(". ");
  delay (wait);
}

@ wild,

The code uploaded fine. When I run it the red LED comes on even though the temp is less than the threshold temp. While the temp is less than the threshold temp, the green status LED is supposed to come on. Thought it might be something in the wiring so I went over it again. I can't see any mistakes. I've included it for reference, just in case I'm missing something. I'm learning, but it's a slow process.

Your wiring diagram shows that the green LED is connected to pin 9. Which is the pin you use to control the red LED in the code.

Hi Perry,

as long as program-execution is not high-speed time-critical you can add serial-output for debugging

This version of your program show almost every detail of what is going on inside your code

#include "DHT_U.h"
#define Type DHT11
int sensePin = 7;
DHT DHTT(sensePin, Type);
float humidity;
float tempC;
float tempF;

int wait = 500;
float thresholdTemp = 79;
int redLed = 9;
int greenLed = 11;

unsigned long previousMillis = 0;
unsigned long interval = 10000;
int redLedState = LOW;



void setup() {
  Serial.begin(115200);
  Serial.println("Serial-Start");
  DHTT.begin();
  pinMode(redLed, OUTPUT);
  pinMode(greenLed, OUTPUT);
}


void loop() {
  unsigned long currentMillis = millis();
  
  humidity = DHTT.readHumidity();
  tempC = DHTT.readTemperature();
  tempF = DHTT.readTemperature(true);
  
  if (tempF < thresholdTemp)
  {
    Serial.print("if (tempF < thresholdTemp) evaluate to true ");
    Serial.print(tempF);
    Serial.print(" < ");
    Serial.print(thresholdTemp);
    Serial.println();
    
    digitalWrite(greenLed, HIGH);
    Serial.print("digitalWrite(greenLed, HIGH);");
    Serial.print("digitalWrite(");
    Serial.print(greenLed);
    Serial.print(", HIGH);");
    
    digitalWrite(redLed, LOW);
    Serial.print("digitalWrite(redLed, LOW);");
    Serial.print("digitalWrite(");
    Serial.print(redLed);
    Serial.print(", LOW);");

    previousMillis = currentMillis;
  }

  // if more time than interval has passed by since last update of previousMillis
  // AND tempF is higher as thresholdTemp
  if ((currentMillis - previousMillis > interval) && (tempF >= thresholdTemp))
  {
    digitalWrite(redLed, HIGH);
    Serial.print("digitalWrite(redLed, HIGH);");
    Serial.print("digitalWrite(");
    Serial.print(redLed);
    Serial.print(", HIGH);");

    digitalWrite(greenLed, LOW);
    Serial.print("digitalWrite(greenLed, LOW);");
    Serial.print("digitalWrite(");
    Serial.print(greenLed);
    Serial.print(", LOW);");    
  }


  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.print(".   TempC: ");
  Serial.print(tempC);
  Serial.print(".   TempF: ");
  Serial.print(tempF);
  Serial.println(". ");
  delay (wait);
}

there is a even better tool it is called WaWiLib
WaWiLib enables monitoring and changing variables on the fly while your code is running

The free version can only monitor one variable. The payd version lots of them and IMHO the price of $15 to 25 is fair

best regards Stefan

So essentially, when the temp reaches the threshold temp, the pump will come on and stay on for a predetermined amount of time,

A more common approach would be not to turn the motor on and off at the same temperature but to introduce some hysteresis into the system.

When the temperature reaches the low threshold turn on the motor but don't turn it off again until it reaches a higher temperature which you have set, which may take some time depending on the environment. Once the motor has been turned off do not turn it on again until the temperature has fallen to the low threshold again

None of this involves any timing and it does not preclude the display of current and target temperatures or, with suitable input, adjustment of the thresholds

If it was some kind of analog bare temperature sensor, then I would add a (low pass) filter. I think that is not needed for the DHT sensor.

A single low pass filter that makes it slow, together with hysteresis might be enough to solve all problems.

To be 100% sure that pump stays on a certain time, then I would use hysteresis and a double single shot millis-timer. A millis-timer to keep it on for a certain time and a millis-timer to keep it off a certain time. Once the pump is have been on during that time, it can of course immediately stop if that is needed. So it will be just a millis-timer the runs a short time after starting or stopping the pump.

I prefer not to weave the millis-timers in the other code that checks the temperature, but have them on their own.

tperry724, there are many possibilities, can you make a choice ?

I recommend reading about state-machines and how to program with them, as this usually simplifies
designing code for such behaviours.

Learn to put code in well named functions, not stuff it all anonymously inside loop() - good program
structure and readability will help enormously both coding initially and if you come back the program
later to enhance/change it.

Thanks all. Much to consider.

@wildbill & @ StefanL38, I tried the code and it uploaded fine. Once the target temp has been reached, the green LED will come on but only AFTER the set interval. I had intended, once the threshold temp has been reached, to have the red LED (as a proxy for the the motor) stay on for the interval time (in this case 10 seconds) regardless of the temp. Once the interval has passed, I'd like to check to see if the temp is still above the threshold temp and if it is, keep the red light to stay on for an additional interval. Does this make sense?

@UkHeliBob Hysteresis? Sounds like something you hear from a dermatologist. Seriously, I'm new but I want to learn. You overview made sense.

@Koepel Double single shot and low pass filters. I've got so much to learn. I'm going to have trouble making a choice.

tperry724:
Once the interval has passed, I'd like to check to see if the temp is still above the threshold temp and if it is, keep the red light to stay on for an additional interval. Does this make sense?

Not really, no. If you want to keep it on longer, perhaps just increase the interval.

tperry724:
Hysteresis?

Thanks, all. I've got some homework to do.

Blanket of snow outside, warm inside, a Friday and I'm tinkering with my Nano. Happy holidays from Pittsburgh, PA.

Best,

Tony

Let me get this straight..

You need to turn on something (PUMP) when a value (TEMP) gets too low. And you would like this to be on for a minimum amount of time when it comes on. Correct?

Would you like, maybe a button that turns it off before the time runs out? Just in case something goes wrong.

This is exactly like the code we ran into, what? Last week? Let me see if I can find that post..

-jim lee

perry did you open the serial monitor and watch the serial-output.

You just wrote that "the code uploaded fine"

if you press sift-Ctrl-M the serial-monitor is opened in another window.
adjust the baudrate to 115200 (that's a standard-value for fast serial transmission)

analysing the serial-output will help a lot

best regards Stefan

Reply #5 was insightful. If you use hysteresis, you don't need to worry about low-pass, one-shot or any other things right now.

You could try this..

I don't have the hardware for the sensor. But the logic [should] be correct.

#include "DHT_U.h"
#include <timeObj.h>


#define LED_PIN      13    // Usual pin number for built in LED. (You wanted 11)
#define PUMP_PIN     9    // Pin number for pump.
#define SENSE_PIN    7    // Pin number for sensor.


DHT DHTT(SENSE_PIN, DHT11);
float thresholdTemp = 79;

timeObj  vTimer(3000,false);      // Setup a 3 sec timer. (Its a float so set it to whatever you need)
bool     pumping;
float    temp;

// Your standard sketch setup()
void setup() {
   
   pinMode(LED_PIN,OUTPUT);         // Set up the LED pin for output.
   digitalWrite(LED_PIN,LOW);       // LED off.
   pinMode(PUMP_PIN,OUTPUT);        // Set up the pump pin for output.
   digitalWrite(PUMP_PIN,LOW);      // Pump off.
   pumping = false;                 // We ain't pumping now.
   DHTT.begin();
}


void doPump(void) {

   temp = DHTT.readTemperature(true);
   if (!pumping) {                        // If we are NOT pumping..
      if (temp < thresholdTemp) {         // If its getting too cold..
         digitalWrite(LED_PIN,HIGH);      // LED on.
         digitalWrite(PUMP_PIN,HIGH);     // Pump on.
         vTimer.start();                  // Fire up timer.
         pumping = true;                  // Note we are now pumping.
      }
   } else {                               // Else we are pumping..
      if (temp >= thresholdTemp) {        // If its getting warm..
         digitalWrite(LED_PIN,LOW);       // LED off.
         if (vTimer.ding()) {             // If the time is up..
            digitalWrite(PUMP_PIN,LOW);   // Pump off.
            pumping = false;              // Note we are now NOT pumping.
         }
      }
   }
}
  

// Your standard sketch loop()
void loop() {
      
   doPump();   // Do the temp/pump thing.
   // And now you can do the display if you like..
}

You'll need LC_baseTools installed from the library manager to get it to compile. And you should check the pin numbers.

-jim lee

Ok, hysteresis seems like the way to go. In my example I have a motor I want to come on when the temperature falls to a certain level outside to deice around a dock. In my code above I changed the goal to have the red LED (the stand in for the motor) come on when the temperature rose above a certain level, indicating the motor was needed. I did this so I could play around with the code. When I want the temp to rise, which I usually set at 77F, I blow into the DHT11. Let's stick with this for easy of troubleshooting. I can always flip flop things later, correct.

I knew enough to be concerned about the motor starting and stopping too much if the temp hovers. So to prevent this I first thought of using the delay function, which might be the easiest solution but not the least bit sophisticated at all. With delay, when the threshold temp is exceeded I'd turn on the red LED, then the motor and then let it run for say 30 minutes. After 30 minutes, the Nano performs another hasty temperature check and if the temp is still over the threshold it continues to run for another 30 minutes. With the delay function, I can't add an LCD screen to see the current temp at any time because it will lock everything down.

Onto hysteresis. I'm gonna need some framework to get this started. I'm struggling to get started. I really don't know how to begin a simple flowchart. So with hysteresis we look at at past states? But we aren't looking at the When of things?

@jimLee I'm going to try your code soon. Probably tomorrow. I'll let you know how it goes. It's 8:36pm where I am.

@jimLee

In order to test the code, I switched from checking to see if it's too cold to seeing if it's too warm. I can then blow into the DHT11 and test my code to see if it's working. It normally returns to "normal" temp after 15 seconds or so. Below is your code, just slightly modified by me.

#include "DHT_U.h"
#include <timeObj.h>


#define LED_PIN      11    // Usual pin number for built in LED. (You wanted 11)
#define PUMP_PIN     9    // Pin number for pump.
#define SENSE_PIN    7    // Pin number for sensor.


DHT DHTT(SENSE_PIN, DHT11);
float thresholdTemp = 79;

timeObj  vTimer(30000,false);      // Setup a 3 sec timer. (Its a float so set it to whatever you need)
bool     pumping;
float    temp;

int wait = 500;

// Your standard sketch setup()
void setup() {
   Serial.begin(9600);
   pinMode(LED_PIN,OUTPUT);         // Set up the LED pin for output.
   digitalWrite(LED_PIN,LOW);       // LED off.
   pinMode(PUMP_PIN,OUTPUT);        // Set up the pump pin for output.
   digitalWrite(PUMP_PIN,LOW);      // Pump off.
   pumping = false;                 // We ain't pumping now.
   DHTT.begin();
}


void doPump(void) {

   temp = DHTT.readTemperature(true);
   if (!pumping) {                        // If we are NOT pumping..
      if (temp > thresholdTemp) {         // If its getting too cold..
         digitalWrite(LED_PIN,LOW);      // LED on.
         digitalWrite(PUMP_PIN,HIGH);     // Pump on.
         vTimer.start();                  // Fire up timer.
         pumping = true;                  // Note we are now pumping.
      }
   } else {                               // Else we are pumping..
      if (temp <= thresholdTemp) {        // If its getting warm..
         digitalWrite(LED_PIN,HIGH);       // LED off.
         if (vTimer.ding()) {             // If the time is up..
            digitalWrite(PUMP_PIN,LOW);   // Pump off.
            pumping = false;              // Note we are now NOT pumping.
         }
      }
   }
}
 

// Your standard sketch loop()
void loop() {
     
   doPump();   // Do the temp/pump thing.
   // And now you can do the display if you like..
  Serial.print("TempF: ");
  Serial.println(temp);
  delay (wait);
}

When I run the code, and the temp is under the threshold temp, the green LED should come on but it does not. If I blow into the DHT11 and the temp exceeds the threshold temp then the red LED comes on as planned. As soon as the temp falls below the threshold temp the green LED comes on (while the red LED is on too as the motor is finishing it's cycle). Can you see why the green LED wouldn't come on in you code. It only comes on after the temp has risen and then fallen back down.

Thank you,

Tony

Oh sorry! I misunderstood how it was supposed to work. Green is OK red is do something. I'll have a go at fixing that.

-jim lee