ATtiny10 Christmas Tree
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)
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:
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.