Friday, April 29, 2022

0000 0000 1001 0011

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!)




No comments:

Post a Comment