Attiny85 Irrigation controller timing issue

I am trying to build a small irrigation controller using an attiny85, two PN2222 transistors, two 12V solenoid valves and a 12V power supply. I have the circuit working properly I think, I have 150 Ohm resistors going from pins 0 and 1 to the base of the transistors with the valves connected from the +12V to the collector and the emitter connected directly to ground. The attiny is powered with a +5V voltage regulator from radioshack.

The valves turn on just fine but they don’t turn off after 5 minutes (300000 milliseconds) like they should. I am wondering if I have something wrong in my programming but it works fine when the attiny is plugged in to the tiny programmer and I use leds to test it. It is burned with the internal 8 MHz clock from High Low Tech.

Here is my program, when first run it should turn valve one on for 5 minutes, wait 10 seconds, turn valve two on for 5 minutes, wait 86400000 milliseconds (one day) from the time first started, repeat…

unsigned long interval = 300000;
int pin1 = 0;
int pin2 = 1;
unsigned long time;
unsigned long watertime = 0;
int value = 0;
int initial = 0;
unsigned long previous = 0;

void setup()
{
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
}

void loop()
{
  time = millis();
  if (initial == 0) {
    if ((time - previous) < interval) digitalWrite(pin1, HIGH);
    if ((time - previous) > interval) digitalWrite(pin1, LOW);
    if ((time - previous) > (interval + 10000)) digitalWrite(pin2, HIGH);
    if ((time - previous) > (2 * interval + 10000))
    {
      digitalWrite(pin2, LOW);
      initial = 1;
      previous = time;
    }
  }
  if ((time - watertime) > 86400000) {
    previous = time;  
    if ((time - previous) < interval) digitalWrite(pin1, HIGH);
    if ((time - previous) > interval) digitalWrite(pin1, LOW);
    if ((time - previous) > (interval + 10000))
    {
      if (value == 0)
      {
        if ((time - previous) < (2 * interval + 10000)) digitalWrite(pin2, HIGH);
        if ((time - previous) > (2 * interval + 10000)) digitalWrite(pin2, LOW);
        watertime = time - (2 * interval + 10000);
        value = 1;
      } 
      else if (value == 1) {
        value = 0;
        watertime = time - (interval + 10000);
      }
    }
  }
}

Thanks for the help.

if ((time - watertime) > 86400000UL)?

time is the variable which holds the millis() value for the current loop iteration and watertime is the variable which holds the millis() value for the last time the valves were turned on. The if statement checks to see if time - watertime (the time between now and when it was last turned on) is greater than 86400000 milliseconds or one day.

If it works good using leds, but now when using the transistors, and solenoids,
Do you have protection diodes across the solenoids?
Can the PN2222 provide enough current to drive the solenoid for 5 minutest, without over heating (burning out) ? It has been running about 98=100 degrees F here lately. May also effect the transistor if out in the garden. Can you hold your finger on the PN2222 without getting a blister.

With a volt meter, check the actual voltage as some 12V supplies may vary. Check the solenoids resistance. Calculate the amps. Is it less than the PN2222 max amps?

Does each solenoid turn on when expected, just never turns off?

The PN2222 transistors are rated for 40V @ 1A peak and the solenoids run at 12V @ 320mA so it should work fine. The transistors are not overheating and neither is the voltage regulator. I have a diode in series with the first valve but not the second. The power supply is providing ~12.3V and when I measure across the solenoid it is getting ~10.5V which is more than enough for them to work properly... the problem is that the attiny is not turning off pin 0 after 5 minutes like it is supposed to.

But if you hook leds to pin0, it does turn off?

Do you have:

  1. A 10kohm resistor from reset of the tiny to VCC .
  2. A 0.1uF capacitor from VCC to GRND on the tiny (as close to the chip as possible)

Dustin, during testing, I would reduce the times, no need to wait for 5 minutes to see if it changes. And if you don't already have it, I would delay about 10 seconds before turning on the first valve, just to make sure it is controlled by the program. You didn't say, is the second valve turning on about 5 minutes after the first one did?

    if ((time - previous) < interval) digitalWrite(pin1, HIGH);
    if ((time - previous) > interval) digitalWrite(pin1, LOW);

Why not make one of the comparisons a bit more inclusive, and just use “else”?
There are a couple of these.

unsigned long watertime = 0;
int value = 0;
int initial = 0;
unsigned long previous = 0;

They already are zero, no need to set them.

When I have the attiny in the tiny programmer on usb power the built in led on pin 0 works perfectly. I have not tried putting leds in the circuit.

I did not have the resistor or the cap. I added them with no difference. But when I left valve 1 unplugged valve 2 worked perfectly, came on at the right time and turned off at the right time. So I am trying moving valve 1 to pin 2 to see if that makes a difference.

I did bring the times down to have the valves on for 1 minute. And valve 2 did not come on unless I left valve 1 unplugged. Now that I moved valve 1 to pin 2 it is working right but valve 2 is not coming on...

So,? does that seem to say, if one valve is stuck on, the second one will not come on?
Or maybe when one valve turns on, the computer locks up and nothing else will happen?

If you have a blinking led (pin 13), you can determine if the computer is still running, or locked up.

It still may be good if you could use two led/resistors rather than the valves. It may be a power problem, and leds may detect that.

The times are working properly now. I just switched valve 1 and valve 2 so that valve 2 runs first. I also added a delay before the first valve opens. Now my problem is that it is stuck in a loop just turning one valve on then off then the other on and off...

Well, I think we are getting close. So the hardware seems to work. We expect something in the sketch.
If you have made changes to the sketch (an seems you have), please upload the current sketch. You changed the timing for testing, Is maybe that what is causing this?

Here is the updated sketch. I decided to just use delays for the initial run because I don’t care about drift. I reset the times that the valves run and now the first one is open for 5 min then 10 sec delay then the second is open for 5 min and that is working perfectly. But after the second one is closed it is supposed to set initial to 1 so that it doesn’t run through that again but that doesn’t seem to be working because after 10 sec it opens the first valve again and repeats the cycle.

unsigned long interval = 300000;
int pin1 = 2;
int pin2 = 1;
unsigned long time;
unsigned long watertime = 0;
int value = 0;
int initial;
unsigned long dayMillis = 86400000;

void setup()
{
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
}

void loop()
{
  time = millis();
  if (initial == 0) {
    delay(10000);
    digitalWrite(pin2, HIGH);
    delay(interval);
    digitalWrite(pin2, LOW);
    delay(10000);
    digitalWrite(pin1, HIGH);
    delay(interval);
    digitalWrite(pin1, LOW);
    initial = 1;
  } 
  else {
    if ((time - watertime) > dayMillis) {
      if ((time - watertime) < dayMillis + (interval)) digitalWrite(pin1, HIGH);
      if ((time - watertime) > dayMillis + (interval)) digitalWrite(pin1, LOW);
      if ((time - watertime) > dayMillis + (interval + 10000))
      {
        if (value == 0)
        {
          if ((time - watertime) < dayMillis + (2 * interval + 10000)) digitalWrite(pin2, HIGH);
          if ((time - watertime) > dayMillis + (2 * interval + 10000)) digitalWrite(pin2, LOW);
          watertime = time - (2 * interval + 10000);
          value = 1;
        } 
        else if (value == 1) {
          value = 0;
          watertime = time - (interval + 10000);
        }
      }
    }
  }
}

Great, looks like all the hardware is working well now.

Just noticed
int initial;
may want to to set that to some value. Then, I don't see where it gets set back to low. Not sure, but maybe.

Alright, I set int initial = 0;

and once it runs through that first block of code the first time initial is supposed to be 1 and it never runs through that again, just skips to the else statement…

Ok, Dustin. I hate to ask again, but can we get your current code? Are we getting close or what?

unsigned long interval = 300000;
int pin1 = 2;
int pin2 = 1;
unsigned long time;
unsigned long watertime = 0;
int value = 0;
int initial = 0;
unsigned long dayMillis = 86400000;

void setup()
{
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
}

void loop()
{
  time = millis();
  if (initial == 0) {
    delay(10000);
    digitalWrite(pin2, HIGH);
    delay(interval);
    digitalWrite(pin2, LOW);
    delay(10000);
    digitalWrite(pin1, HIGH);
    delay(interval);
    digitalWrite(pin1, LOW);
    initial = 1;
  } 
  else {
    if ((time - watertime) > dayMillis) {
      if ((time - watertime) < dayMillis + (interval)) digitalWrite(pin1, HIGH);
      if ((time - watertime) > dayMillis + (interval)) digitalWrite(pin1, LOW);
      if ((time - watertime) > dayMillis + (interval + 10000))
      {
        if (value == 0)
        {
          if ((time - watertime) < dayMillis + (2 * interval + 10000)) digitalWrite(pin2, HIGH);
          if ((time - watertime) > dayMillis + (2 * interval + 10000)) digitalWrite(pin2, LOW);
          watertime = time - (2 * interval + 10000);
          value = 1;
        } 
        else if (value == 1) {
          value = 0;
          watertime = time - (interval + 10000);
        }
      }
    }
  }
}

Ha Dustin, I am on my second six pack, so, take my suggestions with a grain of salt. After the initial run, when do you expect the next action to occur, 24hours ?