Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Electronics ➜ Microprocessors ➜ Simple project - torch-locator

Simple project - torch-locator

Postings by administrators only.

Refresh page


Posted by Nick Gammon   Australia  (23,121 posts)  Bio   Forum Administrator
Date Wed 25 Feb 2015 03:28 AM (UTC)

Amended on Mon 25 Jan 2016 07:57 PM (UTC) by Nick Gammon

Message
A few nights ago the lights went out (power failure). I have torches scattered around the house, but the trick is to find them in the pitch darkness.

It occurred to me that it would be nice if there was a flashing light on or near a torch, so you could head for the light, and find the torch. Hence this project was born.

Design goals




  • Keep power consumption low, so the flashing light could be relied on for a few years.

  • To save power, detect when it was dark, and only flash the light then.

  • Use a lithium "coin" battery because they are compact, and have a long shelf life.


Photos of device


View of processor (battery on table):



Back view showing LED and LDR:



Upside-down, showing battery:



Circuit side, showing parts:




Device sitting on a torch, ready for action:



Schematic




Design notes


To minimize power consumption, the processor sleeps in "power down" mode for two seconds, until it is woken by the watchdog timer. Then it does a ADC read (analog read) of the LDR (light dependent resistor) to see if it dark or not. If it is not dark it goes back to sleep.

To read the LDR it briefly applies power to the voltage divider (does a digitalWrite to D3 (that is, pin 2 on the chip). The ADC reading is taken in sleep mode SLEEP_MODE_ADC, which lets the processor sleep during the reading.

If it is dark, then the code turns timer 0 back on (so that millis() will work) and then turns on the LED, waits 2 mS, and turns it off again. This brief flash is plenty to spot the LED in the dark.

Construction notes


I soldered the whole thing together "dead bug" style on a 8-pin chip socket. This lets you remove the processor and reprogram it if necessary.

I tried to keep components to small sizes to keep the size down, and have less leads that might accidentally break off.

For the LED I used a Adafruit LED Sequin - Warm White which I had to hand. This is a compact LED, with an inbuilt 100 ohm resistor, saving the need to have an extra current-limiting resistor. Also as it turned out, the LED board fitted exactly between pins 4 and 5 of the chip, so all I had to to was drop it onto the pins and solder in place. The polarity is marked on the board with a "+" symbol.


LED "sequins" with built-in resistor:



For the light-detector I used a "50k to 100k" LDR which I had previously purchased from eBay. To measure the resistance you need a voltage-divider so I used a 56k surface-mounted resistor, carefully soldered between pin 2 and pin 5 (ground).

With the LED, LDR and resistor in place, all that remained was to solder Vcc to the + side of the button coin holder, and Gnd to the - side of the holder.

Alternative parts


Of course, you can use any suitable LED with a suitable current-limiting resistor (eg. 100 ohms or thereabouts), and you don't have to use SMD parts if you don't want to.

You can probably use an ATtiny25 or ATtiny45, it is not as if the code is particularly large:


Binary sketch size: 1,396 bytes (of a 8,192 byte maximum)


Prices


(At time of writing)


  • From DigiKey: ATtiny25: $1.56, ATtiny45: $1.45, ATtiny85: $1.69

  • LED Sequins: $3.95 for a pack of 5.

  • 8-pin socket: around 20 cents

  • LDR: around 1 cent

  • Resistor: around 1 cent

  • Button battery holder: around 12 cents

  • CR2032: around 50 cents


Total cost: under $US 4.

Code



// ATtiny85 torch detector
// Author: Nick Gammon
// Date: 25 February 2015

// ATMEL ATTINY 25/45/85 / ARDUINO
// Pin 1 is /RESET
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1 
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

/*

  Pin 2 (PB3) <-- LDR (GL5539) --> Pin 7 (PB2) <----> 56 k <----> Gnd

  Pin 5 (PB0) <---- LED ---> 100 R <-----> Gnd
  
*/


#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte LED = 0;          // pin 5 
const byte LDR_ENABLE = 3;   // pin 2
const byte LDR_READ = 1;     // Ain1 (PB2) pin 7
const int LIGHT_THRESHOLD = 200;  // Flash LED when darker than this

 // when ADC completed, take an interrupt 
EMPTY_INTERRUPT (ADC_vect);
  
// Take an ADC reading in sleep mode (ADC)
float getReading (byte port)
  {
  power_adc_enable() ;
  ADCSRA = bit (ADEN) | bit (ADIF);  // enable ADC, turn off any pending interrupt
  
  // set a2d prescale factor to 128
  // 8 MHz / 128 = 62.5 KHz, inside the desired 50-200 KHz range.

  ADCSRA |= bit (ADPS0) | bit (ADPS1) | bit (ADPS2); 
  
  if (port >= A0)
    port -= A0;
    
#if defined(__AVR_ATtiny85__)  
  ADMUX = (port & 0x07);  // AVcc   
#else   
  ADMUX = bit (REFS0) | (port & 0x07);  // AVcc   
#endif

  noInterrupts ();
  set_sleep_mode (SLEEP_MODE_ADC);    // sleep during sample
  sleep_enable();  
  
  // start the conversion
  ADCSRA |= bit (ADSC) | bit (ADIE);
  interrupts ();
  sleep_cpu ();     
  sleep_disable ();

  // reading should be done, but better make sure
  // maybe the timer interrupt fired 

  // ADSC is cleared when the conversion finishes
  while (bit_is_set (ADCSRA, ADSC))
    { }

  byte low  = ADCL;
  byte high = ADCH;

  ADCSRA = 0;  // disable ADC
  power_adc_disable();
  
  return (high << 8) | low;
  
  }  // end of getReading
  
// watchdog interrupt
ISR (WDT_vect) 
{
   wdt_disable();  // disable watchdog
}  // end of WDT_vect

#if defined(__AVR_ATtiny85__)  
  #define watchdogRegister WDTCR
#else
  #define watchdogRegister WDTCSR
#endif
  
void setup ()
  {
  wdt_reset();  
  pinMode (LED, OUTPUT);
  pinMode (LDR_ENABLE, OUTPUT);
  ADCSRA = 0;            // turn off ADC
  power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
  }  // end of setup

void loop ()
  {
  // power up the LDR, take a reading
  digitalWrite (LDR_ENABLE, HIGH);
  int value = getReading (LDR_READ);
  // power off the LDR
  digitalWrite (LDR_ENABLE, LOW);
  
  // if it's dark, flash the LED for 2 mS
  if (value < LIGHT_THRESHOLD)
    {
    power_timer0_enable ();
    delay (1);  // let timer reach a known point
    digitalWrite (LED, HIGH);
    delay (2); 
    digitalWrite (LED, LOW);
    power_timer0_disable ();
    }
  
  goToSleep ();
  }  // end of loop
  
void goToSleep ()
  {
  set_sleep_mode (SLEEP_MODE_PWR_DOWN);
  noInterrupts ();       // timed sequence coming up

  // pat the dog
  wdt_reset();  
  
  // clear various "reset" flags
  MCUSR = 0;     
  // allow changes, disable reset, clear existing interrupt
  watchdogRegister = bit (WDCE) | bit (WDE) | bit (WDIF);
  // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
  watchdogRegister = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0);    // set WDIE, and 2 seconds delay
  
  sleep_enable ();       // ready to sleep
  interrupts ();         // interrupts are required now
  sleep_cpu ();          // sleep                
  sleep_disable ();      // precaution
  }  // end of goToSleep 


There is a bit of conditional code to allow for testing on a Uno, before migrating to the Attiny85.

Power budget


It is nice to calculate how long this should last before running down the battery.

First, for 99% of the time, it will be sleeping in sleep mode "power down" with the watchdog timer enabled. According to the datasheet that should use 4.4 µA at 3V supply which agrees with what I measured.

Then, every two seconds, it wakes up and does the ADC measurement. This takes around 430 µS, thus it it awake for this fraction of time:


 0.000430 / 2  = 0.000215


According to the datasheet the ADC uses 85 µA at 3V (and 4 MHz). Even though we are running at 8 MHz we can probably use that as a ballpark figure. So that 85µA can be averaged out by multiplying by the amount of time it is awake.


 0.000215 * 85 = 0.018275 


So on average the ADC conversions adds another 0.018 µA to our budget.

In addition to this, if it is dark (say for a third of each day) then we flash the LED for 2 mS every 2 seconds.

Thus the average time the LED is on is for:


 0.002 / 2 / 3 = 0.00033 


I measured the current consumption as being 7 mA, so therefore the average consumption will be:


 0.00033 * 7 = 0.00231 mA


So our total power budget is:


  • Continuous: 4.4 µA
  • ADC conversions: 0.018 µA
  • Flashing LED: 2.31 µA


All up: 6.728 µA

As an estimate, let's assume a CR2032 battery has a capacity of 210 mAH.

Therefore it should run for:


 210 / 0.006728  = 31212.84 hours


Divide by 24 to get days, and 365 to get years and we have:


 31212.84 / 24 / 365 = 3.56 years


There you are! The device should light the way to your torch for over 3 years.

Other applications


If you make up a couple of these, you could deploy them in other places. For example:


  • Emergency exit light - over a door
  • Burglar deterrent - a light flashing in your front room, visible from the street, suggests some sort of monitoring system is active
  • Inside a dummy TV camera. If you mount a TV camera over your front door, pointing at visitors, having a flashing LED makes it look "alive".


Simpler version


Also see Simpler torch flasher which I posted on the Arduino Forum.



// ATtiny85 sleep mode, wake on pin change interrupt or watchdog timer
// Author: Nick Gammon
// Date: 12 October 2013

// ATMEL ATTINY 25/45/85 / ARDUINO
//
//                  +-\/-+
// Ain0 (D 5) PB5  1|    |8  Vcc
// Ain3 (D 3) PB3  2|    |7  PB2 (D 2) Ain1
// Ain2 (D 4) PB4  3|    |6  PB1 (D 1) pwm1
//            GND  4|    |5  PB0 (D 0) pwm0
//                  +----+

#include <avr/sleep.h>    // Sleep Modes
#include <avr/power.h>    // Power management
#include <avr/wdt.h>      // Watchdog timer

const byte LED = 3;  // pin 2

// watchdog interrupt
ISR (WDT_vect)
{
  wdt_disable();  // disable watchdog
}  // end of WDT_vect

void resetWatchdog ()
 {
 // clear various "reset" flags
 MCUSR = 0;    
 // allow changes, disable reset, clear existing interrupt
 WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF);
 // set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
 WDTCR = bit (WDIE) | bit (WDP2) | bit (WDP1) | bit (WDP0);    // set WDIE, and 2 seconds delay
 // pat the dog
 wdt_reset();  
 }  // end of resetWatchdog
 
void setup ()
 {
 resetWatchdog ();  // do this first in case WDT fires
 pinMode (LED, OUTPUT);
 }  // end of setup

void loop ()
 {
 digitalWrite (LED, HIGH);
 delay (1);
 digitalWrite (LED, LOW);
 goToSleep ();
 }  // end of loop
 
void goToSleep ()
 {
 set_sleep_mode (SLEEP_MODE_PWR_DOWN);
 ADCSRA = 0;            // turn off ADC
 power_all_disable ();  // power off ADC, Timer 0 and 1, serial interface
 noInterrupts ();       // timed sequence coming up
 resetWatchdog ();      // get watchdog ready
 sleep_enable ();       // ready to sleep
 interrupts ();         // interrupts are required now
 sleep_cpu ();          // sleep                
 sleep_disable ();      // precaution
 power_all_enable ();   // power everything back on
 }  // end of goToSleep

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


14,306 views.

Postings by administrators only.

Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.