An AVR and photoresistor controlled LEGO Lighthouse

Our local DIY and hardware store gave away some tiny LEGO freebies a while ago. The little lighthouse I chose absolutely had to have an LED in inside its lantern room. Making LEDs blink is simple enough. To make it a little more interesting than the simple “hello world” of programming microcontrollers, it turns itself automatically on and off depending on the light conditions.

DSC 2102

How does it work?

The photoresistor — or light-dependent resistors (LDR) — is connected to an analog input pin AIN1 as part of a voltage divider. A potentiometer, essentially an adjustable voltage divider, is connected to the analog pin AIN0. The darker it gets, the higher the resistance of the LDR, and hence the lower the voltage on the analog pin AIN1.


The analog comparator compares the two voltages on the analog pins 0 and 1. If the voltage on AIN0 is higher than on pin AIN1, then AIN1, the analog comparator output bit ACO of the ACSR register is set. Here is how to turn on an LED on pin PB4 depending on the level of light detected:

#include <avr/io.h>

int main(void)
    DDRB |= _BV(PB4);
    for (;;) {
        int on = ACSR & _BV(ACO);

        if (on)
            PORTB |= _BV(PB4);
            PORTB &= ~(_BV(PB4));

Sleep mode (because battery life)

The problem now is that the battery would not last very long. The ATtiny needs power and there is also current flowing through the LDR and the potentiometer. The amount of this current depends on the intensity of the ambient light and how the trimmer potentiometer is set.

First, sleep mode. Some useful links: AVR and Arduino sleep mode basics, Nick Gammon’s excellent Power saving techniques for microprocessors has lots of code examples, and Sparkfun’s H2OhNo! low-power ATtiny project also uses an ATtiny85.

The main loop with sleep mode instead of a simple delay for the blinking light would look like this:

    for (;;) {
        int blink = ACSR & _BV(ACO);

        if (blink) {
            PORTB |= _BV(PB4);
            PORTB &= ~(_BV(PB4));
            watchdog_enable(WD_2_SECONDS); // sleep for 2 seconds
        } else {
            watchdog_enable(WD_8_SECONDS); // sleep for 8 seconds

If it is dark enough, PB4 will be set to high to turn the LED on. It will stay on for some time (800ms in my case) and when the time is up, the microcontroller is powered down. The watchdog timer will wake it up 2 seconds later. If there is enough light though, the microcontroller is powered down for 8 seconds.

The second problem is the continuous current flowing through the two voltage dividers. This current flows irrespective of the microcontroller being powered down or not. To stop this, I added the switching transistor controlled by port PB3. I got the current consumption during sleep down to 5 microamps. This is very much in line with the Sparkfun project. According to the datasheet I can expect something around 4 microamps. Close enough.

Powerdown supply current

This leaves the LED as the main power consumer. I power my circuit using two N cell batteries. They look like a nice trade off between size and capacity. My prototype of the circuit ran on one set of batteries 24/7 from March 2013 until February 2014.

DSC 2089


Perhaps a microcontroller is complete overkill for a small toy like this, but I just don’t know enough about electronics to design a circuit that would do the same without using a microcontroller. Any ideas how to do this would be welcome.


Schematics and code are on github:

This entry was posted in attiny85, avr, low-power, sleep-mode and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s