Redesigning an old project - a hallway PWM light
A few years ago I made a few hallway lights which definitely favoured function over form. They were so UGLY and also had two power supplies, one for the lights (9V) and one for the microcontroller (3V - 2AA cells).
They worked and were surprisingly robust and useful! I have since improved my coding skills to include better sleeping for the ATTiny13, and my electronics skills have increased to the point where I am more confident running useful lights from a single power supply.
Also in the interim I designed a PCB for the project.
Next I would like to maybe move the LDR to the PIR unit as per this information, and also play around with the number and type of LEDs.
The code is quite simple - perhaps an ASM version would be even slimmer, but for now this seems fine.
// ----------------------------------------------------------------- // 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 }
In the meantime - these updated units are working fine (and so much prettier!)