See solution at bottom
I would like to use an ATTiny85 to control an LED with button clicks. The device would need to run for - at most - 18 hours continuously.
If the LED is off, one click causes it to fade on and back off. If the LED is fading, one click causes it to come fully on and stay on. If the LED is fully on, one click turns it off.
I have included my code below. It works as expected ... for a few minutes. Then the other three LEDs (which I included for debugging) start blinking randomly and the circuit doesn't respond to button presses. If I power cycle the circuit, I get another three minutes of normal behavior.
I currently have the circuit built on a breadboard. I'm powering it with a 5V portable power supply from Adafruit. If it's not clear from the diagram I attached, there's a 0.1uF capacitor connecting the ATTiny's power and ground - with nothing between it and the ATTiny - and a 10K resistor connecting the RESET pin to VCC.
I'm using a Radio Shack Learning Lab as my breadboard. The built-in LEDs also have built-in resistors, but the documentation doesn't tell me what value they are.
I'm using version 0.3.0 of the AbleButtons library. It's included with the Arduino IDE. The library automatically enables the pullup resistor on the button's pin - that's why INPUT_PULLUP isn't specified in setup().
I'm programming the ATTiny85 using the Sparkfun USB Tiny Programmer and the Arduino IDE. The clock is set to 1MHz (internal).
Any help is greatly appreciated. Thank you!
#include <AbleButtons.h>
using Button = AblePullupClickerButton;
#define TRIGGER_PIN 2
Button trigger(TRIGGER_PIN);
//Main LED
#define LED1 0
bool led1 = false;
unsigned int brightness = 0;
//three phases of fade cycle
const unsigned int increaseDuration = 500;
const unsigned int steadyDuration = 500;
const unsigned int decreaseDuration = 500;
//used to calculate brightness
unsigned long increaseElapsed = 0;
unsigned long decreaseElapsed = 0;
//these are modes that determine whether the LED at some point in the fade cycle, steadily on in photo mode,
//or off (it's only entirely off when awaiting input)
#define DARK 0
#define INCREASE 1
#define BRIGHT 2
#define DECREASE 3
#define PHOTO 4
#define CYCLE 5
int mode = DARK;
int cycleMode = INCREASE;
unsigned long cycleStart = 0;
unsigned long cycleDecreaseStart = 0;
//Debug LEDs
#define DEBUG1 3
bool debug1 = false;
#define DEBUG2 1
bool debug2 = false;
#define DEBUG3 4
bool debug3 = false;
void setup() {
// put your setup code here, to run once:
pinMode(LED1, OUTPUT);
pinMode(DEBUG1, OUTPUT);
pinMode(DEBUG2, OUTPUT);
pinMode(DEBUG3, OUTPUT);
//don't need to set the trigger pin as a pullup because the library does that
trigger.begin();
cycleStart = millis();
mode = DARK;
}
void loop() {
// put your main code here, to run repeatedly:
trigger.handle();
//lets us know ATTiny is alive and sane
digitalWrite(DEBUG1, HIGH);
if (trigger.resetClicked()) {
//a little sanity checking
debug2 = !debug2;
digitalWrite(DEBUG2, debug2);
if (mode == DARK) {
mode = CYCLE;
cycleMode = INCREASE;
cycleStart = millis();
} else if (mode == CYCLE) {
mode = PHOTO;
} else if (mode == PHOTO) {
mode = DARK;
} else {
//shouldn't happen
digitalWrite(DEBUG3, HIGH);
}
}
if (mode == CYCLE) {
if (cycleMode == INCREASE) {
increaseElapsed = millis() - cycleStart;
brightness = 255 * (increaseElapsed / float(increaseDuration));
if (brightness > 255) {
//if millis() rolls over, calculated brightness might be oddly high
brightness = 255;
}
analogWrite(LED1, brightness);
if ((millis() - cycleStart) < increaseDuration) {
return;
} else {
cycleMode = BRIGHT;
}
} else if (cycleMode == BRIGHT) {
analogWrite(LED1, 255);
if ((millis() - cycleStart) < (increaseDuration + steadyDuration)) {
return;
} else {
cycleMode = DECREASE;
cycleDecreaseStart = millis();
}
} else if (cycleMode == DECREASE) {
decreaseElapsed = millis() - cycleDecreaseStart;
brightness = 255 - (255 * (decreaseElapsed / float(decreaseDuration)));
if (brightness > 255) {
//if millis() rolls over, calculated brightness might be oddly high
brightness = 0;
}
analogWrite(LED1, brightness);
if ((millis() - (cycleDecreaseStart) < decreaseDuration)) {
return;
} else {
cycleMode = INCREASE;
brightness = 0;
mode = DARK;
}
} else {
//shouldn't happen
//illegal cycle sub-mode
digitalWrite(DEBUG3, HIGH);
}
} else if (mode == PHOTO) {
analogWrite(LED1, 255);
} else if (mode == DARK) {
analogWrite(LED1, 0);
} else {
//illegal mode
//shouldn't happen
digitalWrite(DEBUG3, HIGH);
}
}
Solution
Summary: Circuit didn't draw enough power to keep power supply awake.
The LiPo battery I'm planning to use for this project wasn't here yet, so I thought I'd at least test the code on a 5V portable power supply I use for other portable projects. However, I'd forgotten that this power supply goes to sleep under low loads - in the past, I'd always used it with servos, NeoPixels, etc., that kept it awake!
The power supply doesn't shut off altogether when it's asleep, but when the ATtiny was starved for power it would flicker lights randomly - I could see that it was powered up but not working.
Thank you to everyone who responded!