Wiretapped for your protection

Microcontrolled Simple Pulsating LED

A project that was long over due from a friend and with my costume for a show coming, I needed to sit down and just do it.

Below is information about the hardware, schematics, and code you will need to create this project. Let me know what you think.


  • ATmega88 with ATMega-lite proto board from GizmosUSA.com that I received at the Fall Combots.
  • SFH 310 FA phototransitor
  • Some resistors, 1k, and either 2- 100k Ohm trim pot or a collection to swap in and out
  • LED, in your favorite color and brightness and 1 more if you want an indicator light
  • 2 -.1uF cap
  • CR2032 battery and battery holder
  • 10uH inductor, for the analog power side of the ATMega
  • various jumper wires
  • A MKII ISP programmer for your AVR (may need a seperate setup to program)
  • AVRstudio
  • optional – an Altoids tin for your project.

Schematic is here ->TwinkleStar Schematic

Code is really simple and based on AVR demo included in AVR studio :


 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 * ----------------------------------------------------------------------------
 * Simple AVR demonstration.  Controls a LED that can be directly
 * connected from OC1/OC1A to GND.  The brightness of the LED is
 * controlled with the PWM.  After each period of the PWM, the PWM
 * value is either incremented or decremented, that's all.
 * This code allows for the pulsating behavior above only when the 
 *  ADC0 (sensor) < ADC5 (threshold )
 * Otherwise it it activates a steady LED on PORTB.1.

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#include "iocompat.h"    
#include "adc.h"

extern unsigned char LowLightFlag;

enum { UP, DOWN };

static uint8_t adder[2] = {2, 1};
static uint16_t pwm[2];  
static uint8_t direction[2];

Timer1 Overflow ISRs

This ISR will handle multple (2 right now) LEDS via GPIOs 
ISR (TIMER1_OVF_vect)    

  if (LowLightFlag)

        switch (direction[0])    
            case UP:
                if ((pwm[0] += adder[0]) >= TIMER1_TOP)
                    direction[0] = DOWN;

            case DOWN:
                if (pwm[0]-- == 0)
                    direction[0] = UP;

  OCR1A = pwm[0];      
  PORTB &= ~0x1;

    //turn off pulsating LED
    //Hold Red LED steady
    direction[0]   = UP;
    pwm[0]  = 0;
    OCR1A = pwm[0];
    PORTB |= 0x1;


// Peripheral intialization
void Timer1Init (void)      /* Note [6] */
    /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). */

     * Start timer 1.
     * NB: TCCR1A and TCCR1B could actually be the same register, so
     * take care to not clobber it.
     * Run any device-dependent timer 1 setup hook if present.
#if defined(TIMER1_SETUP_HOOK)

    /* Set PWM value to 0. */
    OCR1A = 0;

    /* Enable OC1 as output. */
    DDROC = _BV (OC1);

    //setup output LED  for ADC
    PORTB = 0xFF;
    DDRB = 0xFF;

  /* Enable timer 1 overflow interrupt. */
    TIMSK1 = _BV (TOIE1);


void HWInit(void)
    sei ();

main (void)
    HWInit ();

    /* loop forever, the interrupts are doing the rest */

    for (;;)      /* Note [7] */

    return (0);


#define ADC_PORT0 0
#define ADC_PORT1 1
#define ADC_PORT2 2
#define ADC_PORT3 3
#define ADC_PORT4 4
#define ADC_PORT5 5
#define ADC_PORT6 6


void ADCSetup();


#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/sleep.h>

#include "adc.h"

static unsigned short LightSensorLevel = 600; //get light level from adc0
static unsigned short LightThresholdLevel = 0; //get threshold from adc5

// aref is used should be the same as vcc
// prescaler of 2
// free running mode
// switch between adc0 and adc5
void ADCSetup()

  ADCSRA = (1<<ADEN) | (1<<ADIE);
  ADCSRB = 0;
  ADMUX = 0; //start with LIGHTSENSOR/adc0
  DIDR0 =  0;


unsigned char LowLightFlag = 0;
//  ADC conversion complete service routine  
  static unsigned short adc_value;
  adc_value = ADCL;   
  /*shift from low level to high level ADC, from 8bit to 10bit*/
  adc_value += (ADCH<<8);

  //switch to different adc channel
  uint16_t temp = ADMUX&0x0F;

  switch (temp)

    LightSensorLevel = adc_value;
    LightThresholdLevel = adc_value;


  if (LightSensorLevel > LightThresholdLevel) 
    LowLightFlag = 0; //light is on
  else LowLightFlag = 1; //light is off

2 Responses

  1. Have you considered using the LEDs themselves as a way to measure the current ambient light intensity? Could save you an analog pin and a component?


    2011/08/22 at 14:37

  2. icis

    Are you suggesting to using a photo diode to measure and feedback into the system?

    There were two things that I considered:

    1. I did not have much time to work on this. I had a costume to complete and not a lot of spare time.
    2. I did not want to be so clever that if it did not work, tuning in the theater would be difficult. Imagine having to change things quickly minutes before going on stage.

    bonus third item: I did not have many of phototransitors I was using. Having to retune passives for a new one seemed painful.

    That said, originally, I planned on making a fully analogue version but I couldn’t get the BOM together in time. I have not decided what to do when I need to make several more of these.

    Thanks for the comment.

    2011/08/27 at 11:06

Leave a Reply

Your email address will not be published. Required fields are marked *