Saturday, July 25, 2020

0000 0000 0011 1001

Tripping the light - fantastic!


After some gentle (?) banter regarding the size and number of buckets of electronics about the place, it was suggested to me by a long time collaborator that the door at the bottom of the staircase into the garage could use some incidental lighting (e.g. before the main lights at the wall are flicked on).

A normal person presumably would go to a hardware store and spend $20 and 15 minutes to fix the problem. Clearly I'm not normal, and so I started a project which could either be labelled:
  1. Lighting the garage upon detecting a human presence, or
  2. Justification (in part) for the many buckets of electronics clogging up the place
The first order of business was planning the physical elements of the project (see video) and then a quick (and dirty) circuit diagram showing the relevant parts orchestrated to achieve the desired outcome.


At the heart of the project is an ATTiny13 (of course) which is asleep. If the door from the stairwell is opened then a hall effect sensor is tripped and the μC wakes up and brings up the LED strip via a transistor. Alternatively from the opposite direction if a warm humanoid stands in front of a PIR then the μC also trips and provides light. I've chosen components that use very little current and so overall the circuit consumes around 500μA when "asleep".


AM312 Mini-PIR at ~15μA

Hall Effect sensor at ~1μA

Voltage regulator at ~1μA 

I then mocked up a prototype, wrote some code and soldered up the "PCB of Goodness".



// -----------------------------------------------------------------
// Description: A strip of Leds connected to a transistor controlled
// by an Attiny13. The μC sleeps most of the time, but is interrupted
// by a PIR on PCINT1, or a Hall Effect sensor on PCINT2. It will then
// light the leds, hold for a bit and and then fade out.
//
// Author: OneCircuit      Date: Thursday 16 July 11:48:26 AEST 2020
// www.onecircuit.blogspot.com
// www.youtube.com/channel/UCTm3eCrN6wk-Ozt9ymyKIIg
// -----------------------------------------------------------------
//
// 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/interrupt.h>           // for interrupt routines
#include <avr/sleep.h>               // the sleep routines

#define StripLED PB0                 // pwm pin
#define HEPin PCINT2                 // Magnetic interrupt pin
#define PIRPin PCINT1                // PIR interrupt pin

volatile boolean triggered = false;  // boolean for keeping track of interrupts

// The led strip 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 gamma8[] = {
  0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4,
  5, 5, 6, 6, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, 14, 14, 15,
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  30, 31, 32, 34, 35, 36, 37, 39, 40, 41, 43, 44, 46, 47,
  48, 50, 51, 53, 54, 56, 58, 59, 61, 63, 64, 66, 68, 69,
  71, 73, 75, 77, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96,
  98, 100, 102, 105, 107, 109, 111, 113, 116, 118, 120,
  123, 125, 127, 130, 132, 134, 137, 139, 142, 144, 147,
  150, 152, 155, 157, 160, 163, 165, 168, 171, 174, 176,
  179, 182, 185, 188, 191, 194, 197, 200, 203, 206, 209,
  212, 215, 218, 221, 224, 227, 230, 234, 237, 240, 243, 247, 250
};

void slowfade(boolean fadein) {

  if (fadein) {
    for (uint8_t lighting = 0; lighting < 150; lighting++) {    // 150 steps
      analogWrite(StripLED, pgm_read_byte(&gamma8[lighting]));  // read from the lookup table
      delay(6);                                                 // increase for a slower fade
    }
  }
  else {
    for (uint8_t lighting = 150; lighting > 0; lighting--) {    // count backwards
      analogWrite(StripLED, pgm_read_byte(&gamma8[lighting]));  // from the lookup table
      delay(80);                                                // increase for a slower fade
    }
  }
}

void powerDown(void)
{
  GIMSK |= (1 << PCIE);                   // activate Pin change interrupts
  PCMSK |= ((1 << HEPin)|(1 << PIRPin));  // 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
  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(100);                             // settle time after waking up
  
}

ISR(PCINT0_vect)
{
  triggered = true;
}

void setup ()
{
  pinMode(HEPin, INPUT_PULLUP);    // configure interrupt pin as input
  pinMode(PIRPin, INPUT_PULLUP);   // configure interrupt pin as input
  pinMode(StripLED, INPUT);        // LED pin input to start

}  // end of setup

void loop () {
  if (!triggered) {
    powerDown(); // call the function that sleeps
  }
  else {
    pinMode(StripLED, OUTPUT);    // LED pin is now output
    slowfade(true);               // fade in
    delay(60000);                 // hold that thought for 1 minute
    slowfade(false);              // fade out
    pinMode (StripLED, INPUT);    // configure transistor pin as input, saves power
    delay(1000);                  // one second before re-trigger
    triggered = false;            // reset boolean
  }
}  // end of code

Finally after testing the new device was installed and currently it lights up when either the door is swung open, or a human is detected via PIR. Mission 1 outlined above - accomplished. Mission 2 - ongoing...



Saturday, July 18, 2020

0000 0000 0011 1000

Monster Mailbag (Part One)


After very little action in the mailbox for weeks (thanks "Pandemania"), and after going away for a week on holidays on our world-wide tour of Tasmania - the postbox was uncharacteristically bursting with mail upon return!

It seems that the freight lines from China are back in action - or maybe the local lines are unclogged after lockdown, but either way we are seeing some items ordered back in March suddenly arriving. I have stopped instigating disputes in AliExpress on the assumption that most stuff will turn up at some time - hopefully before I forget what I was thinking when I pressed the big red "ORDER" button! 

Here is the list of items covered in the video:


There were way too many packages for one video, so here is "Part One" and I'll post the second part in a couple of weeks.




Saturday, July 11, 2020

0000 0000 0011 0111

ATTiny Programming


You do not need a fancy programming shield to program an ATTiny13 or ATTiny85. Early on when I first bought the ATTinys I used an Arduino Uno (I didn't have any Nanos at the time) and simply hooked them up according to instructions I found on the internet. They programmed up fine, but if there were any problems it was usually dodgy breadboards, crude code or me bricking chips with poorly programmed fuses.

Just a Nano and some wires needed

Later I saw the ATTiny ISP Shield from htlinux on the webnets - and I found that this device was way more reliable PLUS it had the added bonus of being able to easily program 14 pin and 20 pin ATTinys (although it seems that in the end this was just an excuse to covet more microcontrollers).

Programming Shield

One day foraging in the AVR backwaters of the internet I discovered the most marvellous programming shield designed by Jia Huang. She made the gerber files available on her github and from memory this was my first (nervous) order I placed to a PCB manufacturer.

When the batch of ten arrived I was so excited that I soldered the first one upside down which was interesting but definitely not functionally useful! It now sits proudly in "The Jar Of Shame™" with my other electronic abominations.

The next one I soldered (properly) worked great and then I was able to program not only my ATTinys, but also for the first time a bare ATMega328 IC (which will be a topic for another blog).

So lovely, and useful

I was pretty happy with this shield as my main programmer (via the UNO) for some time, until I found Łukasz Podkalicki's amazing ATTiny13/85 PCB - and again I had to download the files and have them made, with only a couple of minor modifications.

Two programmers and a wayward capacitor

It allowed me to use a USBasp programmer to quickly load code to the little AVR and as well it opened up many other programming possibilities. For example, I could now use AVRDUDESS to harness the power of avrdude, and also upload directly to the AVR hex files made, for example, from my own handcrafted assembly instructions (e.g. via Gerd's AVR_SIM).

When the freight situation around the world resolves (thank you pandemania!), I'll pop these little beauties onto my Tindie store in case anyone would like to try one - they're great!

In the meantime, see below for a video of me soldering up one of the ATTiny programmers from scratch, and then using all of the options written about above, including the little PCB, to make...er...a blinking LED!





Saturday, July 4, 2020

0000 0000 0011 0110

Yellow 5050 LED - awesome for any candle project


There are many candles of shame scattered around our house - early experiments with multiple LEDs (types and colours) in an attempt to produce the elusive Holy Grail of a lifelike flame emanating from an electronic device. 

In the quest for authentic fakery I firstly tried different colour combinations of orange, red, yellow and warm white searching for a good flame effect. Early recipients of these efforts (sorry...) were sometimes honest in their appraisal and I thank them for their feedback. I suspect a few of those "candles" are carefully filed in truncated inverted conical open ended filing cabinets now.

I tried 3mm, 5mm and various SMD LED formats from different suppliers as part of the experiment. I covered various LED combinations in hot glue, half table tennis balls, grease proof oven paper, tissues, and anything else diffusive that I could find around the house. They're all good in their own way, but ultimately none really were candle-like for various reasons.

All those failures helped focus the requirements for the source of light at the same time I was fiddling with the code looking for acceptable "randomness" to drive the flame.

Early prototype - "white" flame from hot glue

Then one day in 2018 I was skiing virtually through the LED valleys on the internet when I came across a 5050 format LED which seemed to have three pins in and out - surely not! Three LEDs in one - that's heaven for someone looking for a compact controllable efficient package.

I ordered red, orange, yellow, warm white and cold white versions and then sat by the post box in anticipation. All the colours were interesting, but the yellow version was oh so lovely as a candle, and all recent recipients have reported a pleasing realistic candle-like glow emanating from the devices.


The candle project at the time (and still now) has two independently ramping PWM channels, one of which supplies a randomly varying "slow" steady up and down ramp and the other a randomly varying "fast" flickering ramp which gives a little more "life" to the "flame".


The slow ramp signal outputs to two of the LEDs in the package and the fast ramp to the remaining LED. Daredevils could reverse this for a more intense flame. There were some other "breakthroughs" after discovering this LED package. A friend mentioned that the hot glue flame was a bit woeful so I bought some little uniformly round fresnel lenses to help diffuse the glow.


Also I started to put the LED combo on the inside of a glass jar (they used to be hilariously stuck on the outside) and with the inside of the glass jar sprayed with a bit of diffusive white paint, the result was a warm diffuse candle-like ambience. It also helps if the jars are contoured to refract the light more realistically.

Whether the candle is powered by an old battery or rechargeable via a solar panel is irrelevant to the flame quality - but I definitely prefer the solar version for ease of use and sustainability.