Go Down

Topic: Bathroom fan control (Read 1 time) previous topic - next topic

Tobbera

This is my implementation of a Arduino Pro Mini as a bathroom fan control unit. It senses humidity and IR to turn on and off the fan with a relay shield. Everything packed up in a IP67 case. It works verry well. However; i'm not sure what is going to happen with my dependency on millis when it rolls over.












[/url]

Code: [Select]
#include <dht.h>

#define dht_dpin A0 //no ; here. Set equal to channel sensor is on
#define RELAY1 3     
#define HUMIDITYTREASHOLD 55     


float Counter;
long previousMillis = 0;        // will store last time LED was updated

const int ledPin =  13;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
long previousMillisLed = 0;        // will store last time LED was updated
long interval = 300;   

dht DHT;

void setup(){
  pinMode(ledPin, OUTPUT);
  pinMode(PIR_Sensor_Pin, INPUT);     // declare sensor as input
  pinMode(RELAY1, OUTPUT); 
 
  Serial.begin(9600);
   
  digitalWrite(ledPin, HIGH);
  delay(200);
    digitalWrite(ledPin, LOW);
  delay(200);
    digitalWrite(ledPin, HIGH);
  delay(200);
    digitalWrite(ledPin, LOW);
  delay(200);
    digitalWrite(ledPin, HIGH);
  delay(200);
    digitalWrite(ledPin, LOW);
  delay(200);
 
  digitalWrite(RELAY1,HIGH);          // Turns Relay Off
  delay(1000);
    digitalWrite(RELAY1,LOW);          // Turns Relay Off
  delay(1000);
    digitalWrite(RELAY1,HIGH);          // Turns Relay Off
  delay(1000);
    digitalWrite(RELAY1,LOW);          // Turns Relay Off
  delay(1000);
    digitalWrite(RELAY1,HIGH);          // Turns Relay Off
  delay(1000);
 
  Serial.println("Start loggingn\n");
}

void loop(){

  if(millis() - previousMillis > 1000) {
    previousMillis = millis();
    DHT.read11(dht_dpin);
    Serial.print("Current humidity = ");
    Serial.print(DHT.humidity);
    Serial.print("% ");
    Serial.println("temperature = ");
    Serial.print(DHT.temperature);
    Serial.println("C ");
    Serial.print("Counter = ");
    Serial.println(Counter);
    Serial.print("PIR = ");
    Serial.println(analogRead(A1));   
    Serial.print("Timer = ");
    Serial.println((millis()-Counter));
  }


  if ((analogRead(A1)) > 500){
  Counter = millis();
  }

  if ((DHT.humidity >= HUMIDITYTREASHOLD) || ((analogRead(A1)) > 500)){
    digitalWrite(RELAY1, LOW);  // turn Fan ON
  }

  if ((DHT.humidity < (HUMIDITYTREASHOLD - 3)) && ((analogRead(A1)) < 200) && ((millis()-Counter) >= 300000)) {
    digitalWrite(RELAY1, HIGH);  // turn Fan OFF
  }


  if(millis() - previousMillisLed > interval) {
    // save the last time you blinked the LED
    previousMillisLed = millis();   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }

}



Msquare

"timer" variables should be
Code: [Select]
unsigned long previousMillis = 0;        // will store last time LED was updatedThen the magic works - there is no problem with "overflow" - you have written the code right
Code: [Select]
if(millis() - previousMillisLed > interval) {

Peter_n

If you want to understand how unsigned long solves the rollover problem, try the sketch from this: http://playground.arduino.cc/Code/TimingRollover#arithmetic

janost

The thing with millis(), long or not long, rollover problem is that after 52days continously, it will roll over.
That will render your sketch useless for 52days.

The way to deal with it is that your millis can can never be less than your previous stored millis.

If that happens you just make them equal.

Simple.

Peter_n

Did you have a look at my previous post ?
When a unsigned long has a rollover (for example millis() itself) and the previous value did not yet rollover, they still can be substracted and that still will be a positive number, even if the first one is a very low value (because it did a rollover).

Tobbera

Thanks for your input. I will have a look at my code again. Is there any way of "speeding up" millis to test the rollover? Like starting of  millis at a really high value that's just before the point of it rolling over.

Peter_n

If you read Reply #2 and follow that link and run the example at the bottom, you see a real test.

I think it is possible to change millis(), it's just a variable. But it will be hard to test if millis() rollover has influence on the sketch. It is better to check the sketch source code and check that everything is "unsigned long" and that always the newer time is substracted with the older time (and not the other way around).

dtokez

nice idea and implementation. Where do you get 5v from?

Msquare


The thing with millis(), long or not long, rollover problem is that after 52days continously, it will roll over.
That will render your sketch useless for 52days.

The way to deal with it is that your millis can can never be less than your previous stored millis.

If that happens you just make them equal.
Rubbish. :smiley-yell:

If you use unsigned variables and do the subtraction the "rollover" problem does NOT EXIST.

Here is a post where I have a longer explanation.  -> http://forum.arduino.cc/index.php?topic=164178.msg1248507#msg1248507

And back to the posters next question (inspired by janost's FUD)

Is there any way of "speeding up" millis to test the rollover?

You can use unsigned integer for all "timer variables". Use word(millis() ) to get current value. Now you get the rollover every 65.536 seconds. So you test program should have timers at 10 seconds duration or so. (Otherwise you may fall into the trap and confusion of timers "auto retriggering" as described in my longer explanation above)

Tobbera


nice idea and implementation. Where do you get 5v from?


A 230 volt USB wall charger that I ripped apart. But be careful, I made a misstake and I got electricuted, then the fuse in the switchboard went. Not a nice experience.

Coding Badly

Is there any way of "speeding up" millis to test the rollover?


Yes.  Use unsigned short instead of unsigned long.  You will have to consistently cast the value returned from millis.


Or, use this function instead of millis.  The wrap occurs five seconds after your board is reset...

Code: [Select]
unsigned long MyMillis( void )
{
  const unsigned short Offset = (unsigned long)(-1) - 5000ul;

  return( millis() + Offset );
}

Tobbera

Thanks, I will boomark this for future millis-rollover-tolerance-testing. =)

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy