ATtiny85 Light sensor and blink without delay

Hi Guys,

I want to have a battery operated LED turn on when it gets dark, stay on a few hours, then off for 9 hours, the rest of the night, than wait for it to become dark again.

So LED to come on when light levels drop, stay on for a set time, then stay off for a set time regardless of light level and then wait until light levels drop.

My code works as I need except for on intial startup I need to wait for my one of my timers to expire and then it works as designed.

On a test rig with small timers this isn’t a problem but when updated with a 9 hour “off time” it will annoy me. This is the problem I’m waiting for after startup. Even when condition one isnt met. I’m sure its simple but I cant nail it. I had 6 else ifs trying and it was just getting confusing.

   else if ((sensorValue <= 400) && (ledState == LOW) && (currentMillis - previousMillis >= OffTime))

Full Code

#include <avr/sleep.h>

int ledPin =  0;      // the number of the LED pin
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated
long OnTime = 5000;           // milliseconds of on-time
long OffTime = 5000;          // milliseconds of off-time
boolean On = 1;
int Power __attribute__ ((section (".noinit")));

void PowerDown () {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  ADCSRA &= ~(1<<ADEN);       // Turn off ADC to save power
  sleep_enable();
  sleep_cpu();
}
void setup() 
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);  
  Power = !Power;
  if (!Power) PowerDown();
}

void loop()
{
  int sensorValue = analogRead(3); //Read the sensor

  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();
 
  if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
  {
    ledState = LOW;  // Turn it off
    previousMillis = currentMillis;  // Remember the time
    digitalWrite(ledPin, ledState);  // Update the actual LED
  }
   else if ((sensorValue <= 400) && (ledState == LOW) && (currentMillis - previousMillis >= OffTime))
  {
    ledState = HIGH;  // turn it on
    previousMillis = currentMillis;   // Remember the time
    digitalWrite(ledPin, ledState);    // Update the actual LED
  }
}

Using FireTimer.h to implement your software timers will make you code a lot easier to debug (and will look cleaner).

You should also make sure to initialize the LED output state (HIGH or LOW) in your "setup()" function.

I had a look at your FireTimer but I can’t get it working, just confused me more. I get how it would be better but need help intergrating it. I googled but no real life examples out there yet.

My code works, just cant get rid of that initial OffTime delay.

Could it have something to do with the previousMillis variable?, on startup its set to 0, perhaps setting it higher than OffTime... can't test right now.

I have changed the OffTime variable and the startup delay changes with it.

Am I on the right track?

gogreenpower2:
I had a look at your FireTimer but I can't get it working, just confused me more. I get how it would be better but need help intergrating it. I googled but no real life examples out there yet.

It's a very simple library and comes with an example:

#include "FireTimer.h"

FireTimer msTimer;
FireTimer usTimer;

void setup()
{
  Serial.begin(115200);

  msTimer.begin(1000);
  usTimer.begin(1000000, MICRO_SECONDS);
}

void loop()
{
  if(msTimer.fire())
    Serial.println("ms");

  if(usTimer.fire())
    Serial.println("us");
}

I'll explain it here to make it more clear:

Include the library to use:

#include "FireTimer.h"

Instantiate 2 instances of the FireTimer class - one for keeping time with millis() and another for keeping time with micros():

FireTimer msTimer;
FireTimer usTimer;

Initialize the timers to both fire off at 1 second intervals without blocking. The first argument of "begin()" is the timeout and the second (optional) argument of "begin()" is the units of the timeout argument (ms or us):

  msTimer.begin(1000);
  usTimer.begin(1000000, MICRO_SECONDS);

Determine if enough time has elapsed (timeout) based on the return value of "fire()". The "fire()" method returns a bool - true if timeout has occurred and false if not. If a timeout has occurred, it will automatically reset the timer (this "resetting" can be overridden, however). Here, once the timout has occurred, we print "ms" or "us" depending on the timer:

  if(msTimer.fire())
    Serial.println("ms");

  if(usTimer.fire())
    Serial.println("us");

gogreenpower2:
My code works, just cant get rid of that initial OffTime delay.

I'm starting to think this is an XY Problem - you don't millis() or micros(), you need either an RTC or another device to tell your Arduino the current time of day.

enum STATE {
  WAIT_LOW_LIGHT,
  LED_ON,
  LED_OFF
};

STATE state = WAIT_LOW_LIGHT;

int ledPin =  0;                             // the number of the LED pin
unsigned long previousMillis = 0;            // will store last time LED was updated
const unsigned long OnTime = 5000;           // milliseconds of on-time
const unsigned long OffTime = 5000;          // milliseconds of off-time

void setup()
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT); 
}

void loop()
{
  int sensorValue = analogRead(3); // Read the sensor

  unsigned long currentMillis = millis(); // Get the current elapsed time

  switch (state)
  {
    case WAIT_LOW_LIGHT:
      if (sensorValue <= 400)
      {
        digitalWrite(ledPin, HIGH);       // Update the actual LED
        previousMillis  = currentMillis;  // Remember the ON time
        state = LED_ON;
      }
      break;
      
    case LED_ON:
      if (currentMillis - previousMillis >= OnTime)
      {
        digitalWrite(ledPin, LOW);        // Update the actual LED
        previousMillis  = currentMillis;  // Remember the OFF time
        state = LED_OFF;
      }
      break;
      
    case LED_OFF:
      if (currentMillis - previousMillis >= OffTime)
      {
        state = WAIT_LOW_LIGHT;
      }
      break;
  }
}

That works perfectly. Thank you pcbbc. After reading up on this method, it will come in handy for a few other thinigs I need to get going.