Currentmillis not exact

Dear all,

I'm trying to test a small application to integrate into my home automation but I get some weird results.
I want my led on pin 12 to go high for 500ms if input 8 goes high and 5000ms if input 7 goes high. The weird part is that it works but not on 500 or 5000ms, it takes longer.

If I look at the serial print I see first 10 to 12ms difference (interval) and then it starts.

What am I doing wrong because I'm missing something clearly.

Thanks for your help.

//Arduino PIR progamma test

long intervalrelay = 500;// Pulsbreedte voor het aansturen van de relais (milliseconds)
long Millis = 0;
long interval = 0;

void setup () {
  //Initialize the serial port
    Serial.begin(9600);
    delay (1000);

    pinMode(12, OUTPUT);      // sets the digital pin as output
    pinMode(7, INPUT);        //input PIR
    pinMode(8, INPUT);        //input drukknop

}
 
void loop () 
{  
    //Huidige milliseconden
    unsigned long currentMillis = millis();
    
    //serial print for debugging
    Serial.println(currentMillis);
    Serial.println(Millis);
    interval = currentMillis - Millis;
    Serial.println(interval);
    
    if (currentMillis - Millis > intervalrelay)
        {
           digitalWrite(12, LOW);
        }  
    
    if (digitalRead(7) == HIGH)
        {
           digitalWrite(12, HIGH);
           Millis = currentMillis;
           intervalrelay = 5000;
        }
        
    if (digitalRead(8) == HIGH)
        {
           digitalWrite(12, HIGH);
           Millis = currentMillis;
           intervalrelay = 500;
        }      
    delay(10);
}
currentMillis - Millis >= intervalrelay)

?

delay(10);

I'm missing something clearly.

Yup. Or rather, you've got something too much.

Deleted the delay of 10ms and did a minor change from > to >= but still getting the same weird result :s

long Millis = 0;
long interval = 0;

unsigned long ?

The first time your loop function detects the high it will send the output high. It will keep doing this while the input remains high, THEN the countdown begins. So you've got to add the time that the input is high to the begining of the countdown.

So you've got to add the time that the input is high to the begining of the countdown.

Or look at the state change detection example, and do whatever needs doing when the switch BECOMES high, not IS high.

PaulS:
Or look at the state change detection example, and do whatever needs doing when the switch BECOMES high, not IS high.

Yes, my advice is misleading, I'm attempting to explain what IS happening, rather than what should be done to sort it out.

So i need to check when the state changes. Thats why even if I just make a small pulse it still is not right timing. It keeps thinking the output is high so he keeps filling currentmillis in millis.

So if previous state was low and current state = high --> Act!

GeorgesVDR:
So if previous state was low and current state = high --> Act!

I think you've got it :wink:

So now I have update the program it works as intended but what I still don't understand is why does my input (digital read) stay high for about 7 seconds even if i just quickly tap a button (less than a second)

Is my arduino broken or something or is this normal behavior? Due to this I can't react within this 7 second window because he doesn't see any changes of course.

fyi, don't mind the delay of 500ms this is for debugging purposes.

//Arduino PIR progamma test

unsigned long intervalrelay = 500;// Pulsbreedte voor het aansturen van de relais (milliseconds)
unsigned long Millis = 0;
long interval = 0;
int CurrentStatusPIR;
int CurrentStatusDKN;
int PreviousStatusPIR;
int PreviousStatusDKN;

void setup () {
  //Initialize the serial port
    Serial.begin(9600);
    delay (1000);

    pinMode(12, OUTPUT);      // sets the digital pin as output
    pinMode(7, INPUT);        //input PIR
    pinMode(8, INPUT);        //input drukknop
    PreviousStatusPIR = digitalRead(7);
    PreviousStatusDKN = digitalRead(8);


}
 
void loop () 
{  
    //Huidige milliseconden
    unsigned long currentMillis = millis();
    
    //serial print for debugging
    Serial.println(currentMillis);
    Serial.println(Millis);
    interval = currentMillis - Millis;
    Serial.println(interval);
    
    if (currentMillis - Millis > intervalrelay)
        {
           digitalWrite(12, LOW);
        }  
    
    CurrentStatusPIR = digitalRead(7);
    CurrentStatusDKN = digitalRead(8);
    
    Serial.println("CurrentStatusPIR");
    Serial.print(CurrentStatusPIR);
    Serial.println(" ");
 
    if (CurrentStatusPIR == HIGH && PreviousStatusPIR == LOW)
        {
           digitalWrite(12, HIGH);
           Millis = currentMillis;
           intervalrelay = 50000;
        }
    
    PreviousStatusPIR = digitalRead(7);
    
    Serial.println("PreviousStatusPIR");
    Serial.print(PreviousStatusPIR);
    Serial.println(" ");
        
    if (CurrentStatusDKN == HIGH && PreviousStatusDKN == LOW)
        {
           digitalWrite(12, HIGH);
           Millis = currentMillis;
           intervalrelay = 500;
        } 
    
    PreviousStatusDKN = digitalRead(8);
    
        
   delay(500);
        
}

Have you got a resistor between your input pin and GND. The value isn't critical, but something around 10k would be fine.

I don't understand why but it works like a charm. Do you force the input back down due to this resistor? And is this common practice because I didn't use this before :slight_smile:

Also:
get into the habit of using unsigned long when dealing with millis stuff.

long interval = 0; //Change to, unsigned long interval = 0UL;

interval = currentMillis - Millis;

http://playground.arduino.cc/CommonTopics/PullUpDownResistor

GeorgesVDR:
I don't understand why but it works like a charm. Do you force the input back down due to this resistor? And is this common practice because I didn't use this before :slight_smile:

Yes it's more than common practice, it's practically prescribed practice. You shouldn't have an input "floating". So for things like buttons you'll have

EITHER
Input connected to GND via a resistor and then have the button apply 5v
OR
Input connected to 5v via a resistor then have the button apply GND

There are built in PULLUP resistors to support this second method. So if you connect your buttons to GND, then you can use the PULLUP resistor for the pin by setting its pinMode (pinNumber, INPUT_PULLUP); Using this method you don't need the external resistor, but your input will be active LOW (ie HIGH means button is NOT being pressed).