Electronic – arduino – Millis() Function with Relay Connected to Motor

arduinomicrocontrollermotorrelay

I connected my motor to a relay module and everything is working fine, but the timer that I created is what is causing trouble. What I wish to achieve is for my motor to activate after 5 seconds of the light being on and stay on until the photoresistor no longer detects light. It is able to achieve that, but after a few trials, the relay activates as soon as the photoresistor detects light. I can temporarily fix this by pressing the reset button, but again after a few trials, it is the same again.

I have provided a video:
https://youtu.be/XmRjOIuPIRc

int analogValue;
int voltage;
int timer = millis();
void setup()
{
  pinMode(A0, INPUT);
  pinMode(7, OUTPUT);
  Serial.begin(9600);
  digitalWrite(7, LOW);
}

void loop()
{
  analogValue = analogRead(A0);
  analogWrite(7, voltage);
  if(analogValue > 200){
    if((millis() - timer) >10000){
    digitalWrite(7, HIGH);
    }
  }
      else{
        timer = millis();
       digitalWrite(7, LOW);
      }
}

Best Answer

As Brian Drummond correctly suspected, this is an integer overflow issue.

On the ATmega Arduino, an int is a 16 bit signed type which will overflow in just over 32 seconds.

As a result, the millis() function instead returns an unsigned long which will overflow in 49.7 days.

If you change the type of "timer" to unsigned long then things will work in the short term.

Additionally, because you performed a subtraction before comparison, they will even work in the overflow/wraparound case, because you'll still end up with a valid time difference to compare against your threshold of 10000.

At first glance one might think that you existing code would be similarly wraparound safe, too. But it isn't, because the math of wraparounds doesn't work right between an unsigned long and a (signed) int.

Additionally it probably has no bearing on your issue, the following line of code serves no useful purpose and should be removed:

analogWrite(7, voltage);