// -----------------------------------------------------------------
// Description: A couple of parallel Leds connected to a transistor
// controlled by an Attiny13. The μC sleeps most of the time, but is
// interrupted by a PIR on PB2, The μC then checks the light
// levels. If it's light then it will sleep again, but if it's dark
// it will light the leds slowly, hold for awhile and and then fade
// out.
//
// Author: OneCircuit Date: Thu 31 Mar 2022 18:28:44 AEDT
// -----------------------------------------------------------------
//
// ATMEL ATTINY13 μC
//
// +-\/-+
// RESET--ACD0--5/A0--PCINT5--PB5 1| |8 VCC
// CLKI--ACD3--3/A3--PCINT3--PB3 2| |7 PB2--PCINT2--2/A1--SCK--ADC1
// ACD2--4/A2--PCINT4--PB4 3| |6 PB1--PCINT1---1---MISO--OCOB--INT0*
// GND 4| |5 PB0--PCINT0---0---MOSI--OCOA*
// +----+
// * indicates PWM port
//
#include <avr/pgmspace.h> // for reading the progmem values
#include <avr/sleep.h> // the sleep routines
#define LEDs PB0 // pwm pin
#define InterruptPin PB2 // interrupt pin
#define photoresistor A2 // A2 analog in
// The leds will fade exponentially to compensate for human perception,
// which is not linear. You can calculate as a curve, but float
// values will blow the little Attiny13 out of the water, so a lookup
// table in progmem makes more sense for saving memory.
const uint8_t PROGMEM fadevalues[] = {
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9,
9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13,
13, 13, 13, 14, 14, 14, 15, 15, 15, 16, 16, 16, 17, 17, 18, 18,
18, 19, 19, 20, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25,
26, 27, 27, 28, 28, 29, 30, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 57, 58, 59, 60, 62, 63, 64, 66, 67, 69, 70, 72,
73, 75, 76, 78, 80, 81, 83, 85, 87, 88, 90, 92, 94, 96, 98, 100,
103, 105, 107, 109, 112, 114, 117, 119, 122, 124, 127, 130, 132, 135, 138, 141,
144, 147, 150, 153, 157, 160, 164, 167, 171, 174, 178, 182, 186, 190, 194, 198,
202, 206, 211, 215, 220, 224, 229, 234, 239, 244, 249, 255, 255, 255, 255, 255 };
void powerDown(void)
{
GIMSK |= (1<<PCIE); // activate Pin change interrupts
PCMSK |= (1<<InterruptPin); // sets the Pin change interrupt mask
ADCSRA &= ~(1<<ADEN); // turn off ADC
ACSR|=(1<<ACD); // turn off Analog comparator.
sei(); // enable global interrupts
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep deeply little one
BODCR |= (1<<BODS)|(1<<BODSE); // turn off brownout detection
BODCR |= (1<<BODS);
BODCR &= ~(1<<BODSE);
sleep_enable(); // enable sleep mode
sleep_mode(); // system sleeps here
sleep_disable(); // ISR routine returns here so wake up
GIMSK &= ~(1<<PCIE); // deactivate Pin change interrupts
ADCSRA |= (1 << ADEN); // turn on ADC
ACSR = (0<<ACD); // turn on Analog comparator.
delay(50); // settle time
// read the input pin, local variable saves memory
uint16_t val = analogRead(photoresistor);
if(val < 250) {
pinMode(5,OUTPUT);
slowfade(true); // fade in
delay(30000); // hold that thought
slowfade(false); // fade out
pinMode(5,INPUT_PULLUP);
}
}
void slowfade(boolean fadein){
if (fadein) {
for (uint8_t lighting = 0; lighting < 255; lighting++){
analogWrite(LEDs, pgm_read_byte(&fadevalues[lighting])); // read from the lookup table
delay(5); // increase for a slower fade
}
}
else {
for (uint8_t lighting = 255; lighting > 0; lighting--){ // count backwards
analogWrite(LEDs, pgm_read_byte(&fadevalues[lighting])); // from the lookup table
delay(50); // increase for a slower fade
}
}
}
ISR(PCINT0_vect)
{
// wake up little one...
}
void setup ()
{
// all inputs and pullups to save power
pinMode(1,INPUT_PULLUP);
pinMode(2,INPUT_PULLUP);
pinMode(3,INPUT_PULLUP);
pinMode(5,INPUT_PULLUP);
pinMode(6,INPUT_PULLUP);
pinMode(7,INPUT_PULLUP);
} // end of setup
void loop () {
powerDown(); // call the function that sleeps
}