ATtiny10 Christmas Tree

New PCB for Christmas  Attiny10

New PCB from OshPark for  ATtiny10 Christmas tree.

Christmas Tree in protective shell.

2021 ATtiny10 Christmas Tree

I love Christmas Trees.. So I've done many fire fly jars with ATtiny85's. I wanted to make a miniature Christmas tree that would run off a watch battery (CR2032).  I was new to Attiny10 and was able to get it sleep at .09uA.  So I started from there. Did the typical Charlie plex to get 6 individual lights from 3 pins. I doubled up on the colored lights making a total of 11 ( 10 colored and 1 white for a Star). 

The glassy looks on LED and glue used was UV glue.. Looks like glass when done.

The code is such that now with firmware v1.3 you can now use the reset button as a mode button and it works great. I have 5 modes on it. 

* 1 diagnostic light flash loops 20 times

* 2 All lights on for approx. 1 min 45 sec

* 3 Wild card (does modes 2-4)

* 4 Faster Slower loops 16 times

* 5 Flash on and off


Updated 08-24-2022:

Code re-write to port to Microchip studio IDE. (which is most up to date and optimized)


Updated 12-24-2021:

Added 5th mode with flashing lights (except Star) for about 1 minute 10 sec. and lengthened time for other modes for longer display. Also PCB available at Oshpark  https://oshpark.com/profiles/shermluge Version 4.3 is current PCB.

For Microchip Studio use this code: (with -Os Optimization)

/* * ATtiny10-Christmas-tree-w_deepsleep-C-version.c * * UPDATED: 6/2/2022 19:17:58 * Moved to coding it in Microchip Studio * UPDATED 8/22/2022 * Several changes to compile lighter in Microchip studio */ /* * Tiny Christmas Tree * Sherman Stebbins * 2021-10-21 *  * Firmware v1.4 updated 08/25/2022 * Notes updated 12/10/21 * Added new flash mode and extended times 12/24/21 * added use of reset button to change modes: * 1 diagnostic light flash loops 20 times * 2 All lights on for approx 1 min 45 sec * 3 Wild card (basically the same as V1) * 4 Faster Slower loops 10 times * 5 Flash all but star for about 1 minute 10 sec. //had to remove due to memory. *  * Attiny10;                +====+;     SCK -> PB0 |*   | PB3 (RESET);            GND |    | Vcc;    MOSI -> PB1 |    | PB2 ;                +====+
Fixeddoesnt matter on mhz setting
Test showed in sleep .09uA !!!!!! */#define F_CPU 1000000UL //was below, moved above and untested. if goes super fast, just change delays.#include <util/delay.h>#include <avr/io.h>//#include <avr/interrupt.h>
#define LFSR_SEED  (91)#define MaxLights 6#define LINE_A 0 // (PB0) #define LINE_B 1 // (PB1)#define LINE_C 2 // (PB2)#define starDelay 2#define Star 5#define red 4#define blue2 3#define blue1 2#define grn2 1#define grn1 0#define EXT_RESET (1 << EXTRF)
volatile unsigned char count __attribute__((section(".noinit"))); // Not cleared on RESET
//DDRB direction config for each LED (1 = output)const uint8_t led_dir[7] = {
  ( 1<<LINE_A | 1<<LINE_B ), //green  ( 1<<LINE_A | 1<<LINE_B ), //green  ( 1<<LINE_A | 1<<LINE_C ), //blue  ( 1<<LINE_A | 1<<LINE_C ), //blue  ( 1<<LINE_B | 1<<LINE_C ), //White/red  ( 1<<LINE_B | 1<<LINE_C ), //White/red};
//PORTB output config for each LED (1 = High, 0 = Low)const uint8_t led_out[7] = {   //H   L  ( 1<<LINE_A ), //LED  0 grn1  PB0-PB1  ( 1<<LINE_B ), //LED  1 grn2  PB1-PB0  ( 1<<LINE_A ), //LED  2 blue1 PB0-PB2  ( 1<<LINE_C ), //LED  3 blue2 PB2-PB0  ( 1<<LINE_C ), //LED  4 red   PB2-PB1  ( 1<<LINE_B ), //LED White    PB1-PB2};
void light_led(uint8_t led_num);void leds_off(void);void allOn(int loops);void flash(uint8_t loops);void my_delay_ms(uint8_t n);void flashStar(uint8_t flashCount);void lightCheck(void);void wildCard(uint8_t howMany);void goToSleep(void);
int main(void){
  //reset status page 52 datasheet:  if ((RSTFLR & EXT_RESET) != 0) {    // If External RESET then increment count and output to pins    RSTFLR = RSTFLR & ~EXT_RESET; //for attiny10    count++; //change mode  }   if (count>4){    count=0;  }    while(1){  switch(count){ //select what mode after reset button hit    case 0:      flashStar(1);      for(int i=0;i<20;i++){        lightCheck();      }    break;
    case 1:          flashStar(2);        allOn(11500); //9500 about 1 minute 45 seconds     500 = 5 sec about      break;
    case 2:        flashStar(3);        wildCard(5);           break;
    case 3:       flashStar(4);//   uint8_t k = 16;//   while(k--){      for(uint8_t k=0;k<16;k++){           for(uint8_t i=0;i<40;i++){          for(uint8_t j = 0;j<MaxLights;j++){            light_led(j);            my_delay_ms(2*i);            light_led(Star);            my_delay_ms(starDelay);                }              }          for(uint8_t i=40;i>0;i--){          for(uint8_t j = 0;j<MaxLights;j++){            light_led(j);            my_delay_ms(2*i);            light_led(Star);            my_delay_ms(starDelay);                }              }      }      break;          case 4:        flashStar(5);        flash(160);      break; 
    default:           break;         }        allOn(400); //4 sec    leds_off();    goToSleep(); //go to sleep.. no wake up other then reset.  }}
void light_led(uint8_t led_num) {    DDRB = led_dir[led_num];    PORTB = led_out[led_num]; }
void leds_off(void) { DDRB = 0; PORTB = 0; }
void allOn(int loops){ while(loops--){  //for(int i=0;i<loops;i++){    for(int j=0;j<MaxLights;j++){      light_led(j);      _delay_ms(1);      light_led(Star); //keep white light brightest      _delay_ms(1);         }  }   leds_off();}


void flash(uint8_t loops){  //for(int i=0;i<loops;i++){ while(loops--){ allOn(30); // uint8_t j=100; // while(j--){ for(uint8_t j=0;j<100;j++){ light_led(Star); // _delay_ms(1); leds_off(); }    _delay_ms(250);      }   leds_off();}
void my_delay_ms(uint8_t n){  while(n--) {    _delay_ms(1);  }}
void flashStar(uint8_t flashCount){    /*  for(uint8_t i=0;i<=flashCount;i++){        light_led(Star);        _delay_ms(250);        leds_off();        _delay_ms(250);        }*/ while(flashCount--){ light_led(Star); _delay_ms(250); leds_off(); _delay_ms(250); }  _delay_ms(700);}
//more of a diagnostic to slowley flash each set of lights:void lightCheck(void){      light_led(Star);    _delay_ms(500);    light_led(Star);    _delay_ms(500);
    for(int i=0;i<MaxLights;i++){      light_led(i);      _delay_ms(500);    }}
//Kind of a mix of everything.void wildCard(uint8_t howMany){ while(howMany--){ for(uint8_t i=0;i<40;i++){ for(uint8_t j = 0;j<MaxLights;j++){   light_led(j);   my_delay_ms(2*i);   light_led(Star);   my_delay_ms(starDelay);       }       } allOn(500); for(int i=0;i<10;i++){ light_led(0); _delay_ms(80); light_led(blue1); _delay_ms(80); light_led(red); _delay_ms(80);         light_led(grn2); _delay_ms(80); light_led(Star); _delay_ms(80); light_led(blue2);
for(int i=0;i<MaxLights;i++){   light_led(i);   _delay_ms(200); } allOn(800);   for(uint8_t i=0;i<40;i++){   for(uint8_t j = 0;j<MaxLights;j++){ light_led(j); my_delay_ms(2*i); light_led(Star); my_delay_ms(starDelay);         }       }   for(uint8_t i=40;i>0;i--){ for(uint8_t j = 0;j<MaxLights;j++){ light_led(j); my_delay_ms(2*i); light_led(Star); my_delay_ms(starDelay); } } }}
void goToSleep(void){   SMCR |= (1<<2); //SMCR.SM bit 2 (010) Power-down  SMCR |= (1<<0); //SMCR.SE =1; SET JUST before Sleep starts    __asm__ __volatile__ ( "sei" "\n\t" :: ); //Sleep instruction to put controller to sleep (found this syntax later, probably more proper)  __asm__ __volatile__ ( "sleep" "\n\t" :: ); //Sleep instruction to put controller to sleep (found this syntax later, probably more proper) }

For Arduino IDE use this code:

/* * Tiny Christmas Tree * Sherman Stebbins * 2021-10-21 *  * Firmware v1.3 updated 12/24/21 * Notes updated 12/10/21 * Added new flash mode and extended times 12/24/21 * added use of reset button to change modes: * 1 diagnostic light flash loops 20 times * 2 All lights on for approx 1 min 45 sec * 3 Wild card (basically the same as V1) * 4 Faster Slower loops 10 times * 5 Flash all but star for about 1 minute 10 sec. *  * ATtiny10;                +====+;     SCK -> PB0 |*   | PB3 (RESET);            GND |    | Vcc;    MOSI -> PB1 |    | PB2 ;                +====+
FixedTest showed in sleep .09uA !!!!!! */#define F_CPU 1000000UL
#include <util/delay.h>
#define LFSR_SEED  (91)#define MaxLights 6#define LINE_A 0 // (PB0) #define LINE_B 1 // (PB1)#define LINE_C 2 // (PB2)#define starDelay 2#define Star 5#define red 4#define blue2 3#define blue1 2#define grn2 1#define grn1 0#define EXT_RESET (1 << EXTRF)
volatile unsigned char count __attribute__((section(".noinit"))); // Not cleared on RESET
//DDRB direction config for each LED (1 = output)const uint8_t led_dir[7] = {
  ( 1<<LINE_A | 1<<LINE_B ), //green  ( 1<<LINE_A | 1<<LINE_B ), //green  ( 1<<LINE_A | 1<<LINE_C ), //blue  ( 1<<LINE_A | 1<<LINE_C ), //blue  ( 1<<LINE_B | 1<<LINE_C ), //White/red  ( 1<<LINE_B | 1<<LINE_C ), //White/red};
//PORTB output config for each LED (1 = High, 0 = Low)const uint8_t led_out[7] = {   //H   L  ( 1<<LINE_A ), //LED  0 grn1  PB0-PB1  ( 1<<LINE_B ), //LED  1 grn2  PB1-PB0  ( 1<<LINE_A ), //LED  2 blue1 PB0-PB2  ( 1<<LINE_C ), //LED  3 blue2 PB2-PB0  ( 1<<LINE_C ), //LED  4 red   PB2-PB1  ( 1<<LINE_B ), //LED White    PB1-PB2};
int main(void){
  //reset status page 52 datasheet:  if ((RSTFLR & EXT_RESET) != 0) {    // If External RESET then increment count and output to pins    RSTFLR = RSTFLR & ~EXT_RESET; //for attiny10    count++; //change mode  }   if (count>4){    count=0;  }    while(1){  switch(count){ //select what mode after reset button hit    case 0:      flashStar(0);      for(int i=0;i<20;i++){        lightCheck();      }    break;
    case 1:          flashStar(1);        allOn(11500); //9500 about 1 minute 45 seconds     500 = 5 sec about      break;
    case 2:        flashStar(2);        wildCard(5);           break;
    case 3:       flashStar(3);      for(uint8_t k=0;k<16;k++){           for(uint8_t i=0;i<40;i++){          for(uint8_t j = 0;j<MaxLights;j++){            light_led(j);            my_delay_ms(2*i);            light_led(Star);            my_delay_ms(starDelay);                }              }          for(uint8_t i=40;i>0;i--){          for(uint8_t j = 0;j<MaxLights;j++){            light_led(j);            my_delay_ms(2*i);            light_led(Star);            my_delay_ms(starDelay);                }              }      }      break;          case 4:        flashStar(4);        flash(160);      break; 
    default:     // hearBeat();      break;         }        allOn(400); //4 sec    leds_off();    goToSleep(); //go to sleep.. no wake up other then reset.  }}
void light_led(uint8_t led_num) {    DDRB = led_dir[led_num];    PORTB = led_out[led_num]; }
void leds_off() { DDRB = 0; PORTB = 0; }
void allOn(int loops){  for(int i=0;i<loops;i++){    for(int j=0;j<MaxLights;j++){      light_led(j);      _delay_ms(1);      light_led(Star); //keep white light brightest      _delay_ms(1);         }  }   leds_off();}


void flash(uint8_t loops){  for(int i=0;i<loops;i++){        allOn(30);    for(int j=0;j<100;j++){      light_led(Star);      _delay_ms(1);      leds_off();    }    //_delay_ms(250);      }   leds_off();}
void my_delay_ms(uint16_t n){  while(n--) {    _delay_ms(1);  }}
void flashStar(uint8_t flashCount){      for(uint8_t i=0;i<=flashCount;i++){        light_led(Star);        _delay_ms(250);        leds_off();        _delay_ms(250);        }  _delay_ms(700);}/*static uint16_t prng_lfsr16(void){        static uint16_t cnt16 = LFSR_SEED;        return (cnt16 = (cnt16 >> 1) ^ (-(cnt16 & 1) & 0xB400));}*/
//more of a diagnostic to slowley flash each set of lights:void lightCheck(void){      light_led(Star);    _delay_ms(500);    light_led(Star);    _delay_ms(500);
    for(int i=0;i<MaxLights;i++){      light_led(i);      _delay_ms(500);    }}
//Kind of a mix of everything.void wildCard(uint8_t howMany){  for(uint8_t k=0;k<=howMany;k++){    for(uint8_t i=0;i<40;i++){        for(uint8_t j = 0;j<MaxLights;j++){          light_led(j);          my_delay_ms(2*i);          light_led(Star);          my_delay_ms(starDelay);              }            }    allOn(500);    for(int i=0;i<10;i++){      //int ranNumWhite=(prng_lfsr16()/30);//random number //remarking changed mem from 900 to 876      //if (ranNumWhite & 0x01) { // odd number        light_led(0);        _delay_ms(80);        light_led(blue1);        _delay_ms(80);        light_led(red);        _delay_ms(80);              //}else{        light_led(grn2);         _delay_ms(80);        light_led(Star);         _delay_ms(80);        light_led(blue2);      } 
    //} 
    for(int i=0;i<MaxLights;i++){      light_led(i);      _delay_ms(200);    }    allOn(800);        for(uint8_t i=0;i<40;i++){      for(uint8_t j = 0;j<MaxLights;j++){        light_led(j);        my_delay_ms(2*i);        light_led(Star);        my_delay_ms(starDelay);            }          }        for(uint8_t i=40;i>0;i--){      for(uint8_t j = 0;j<MaxLights;j++){        light_led(j);        my_delay_ms(2*i);        light_led(Star);        my_delay_ms(starDelay);            }          }  }}
void goToSleep(void){   SMCR |= (1<<2); //SMCR.SM bit 2 (010) Power-down  SMCR |= (1<<0); //SMCR.SE =1; SET JUST before Sleep starts    sei() ; //set Global Interrupt Enable  //__asm__ __volatile__("sleep") ; //enter sleep, waiting for interrupt -- This worked great!!!  __asm__ __volatile__ ( "sleep" "\n\t" :: ); //Sleep instruction to put controller to sleep (found this syntax later, probably more proper) }



A Penny, A Grain of rice, and the Attiny10 microcontroller.