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.
2021 ATtiny10 Christmas Tree
Very first one on a proto board. The rest are on a PCB I designed and have oshpart.com print for me.
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.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
; +====+
Fixed
doesnt 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) //not used remarked 9/17/2025
#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://Diagnostic
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);
my_delay_ms(200);
}
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:
A Penny, A Grain of rice, and the Attiny10 microcontroller.