/* * ATtiny10-fireflies-4-led.c //Now 6 led's all PWM :) * * Total re-write of my past Firefly's * WORKS AWSOME * Current consumption when on is about 1mA!! and in the microamps * whith the BU7230 Comparitor consuming 29uA and ATtiny10 consuming .15uA * during sleep but powered up at night. * * * * Updated 8/8/2023: * All issue's fixed, just waiting for PCB from Oshpark. * Also, Changed sleep to 5 modes from six to add more of a random * appearance. I might change the hold mode from 6 to 7 to also make * more of a random appearance (But probably don't because of the odd number for fly[]). * * Despite sudo random. * * Created: 8/4/2023 13:26:54 * Author : Sherman Stebbins */
#include <avr/io.h>#include <avr/interrupt.h>#define F_CPU 1000000UL#include <util/delay.h>
#define INIT 0#define RAMPUP 1#define HOLD 2#define RAMPDOWN 3#define BLANK 4
void ledOff(void);void initTimer0(void);void initTimer1(void);void ledOn(uint8_t ledPort);void goToSleep(uint8_t);
//Maybe make volatile?, Const? Worked making const :)const uint8_t fly[] = {2,1,5,3,4,0,5,4,0,2,1,5,4,1,2,4,1,3,5,3,3,4}; //sudo random.
volatile unsigned char nextFly __attribute__((section(".noinit"))); // Not cleared on RESET//volatile uint8_t nextFly __attribute__((section(".noinit"))); // Not cleared on RESETvolatile unsigned char nextHold __attribute__((section(".noinit"))); // Not cleared on RESETvolatile unsigned char nextSleep __attribute__((section(".noinit"))); // Not cleared on RESET//uint8_t nextFly = 0;//volatile uint8_t nextHold = 0;//volatile uint8_t nextSleep = 0;volatile uint8_t led = 0;volatile uint8_t flyMode = INIT;volatile uint16_t Resolution = 2000;
int main(void){ CCP=0xD8; WDTCSR &= ~(1<<WDE); //must have or won't sleep WDTCSR &= ~(1<<WDIE); uint16_t brightness = 0; ledOn(led); while (1) { switch (flyMode){ case INIT: brightness=1; nextFly++; if(nextFly > sizeof(fly)-1){ nextFly=0; } led = fly[nextFly]; //for testing: //led++; //if (led>5){led=0;} ledOn(led); flyMode = RAMPUP; break; case RAMPUP: if(brightness > 300){ brightness+=20; } if(brightness >= Resolution ){ flyMode = HOLD; break; } _delay_ms(10); OCR0B=brightness; OCR0A=brightness; brightness+=10; break; case HOLD: nextHold++; if(nextHold > 5){ nextHold = 0; }
if(nextHold == 0){ _delay_us(1); Resolution = 4000; }else if(nextHold == 1){ _delay_ms(10); Resolution = 3000; //4000 }else if(nextHold == 2){ //_delay_ms(100); Resolution = 5000; //6000 }else if(nextHold == 3){ //_delay_ms(200); Resolution = 6000; }else if(nextHold == 4){ //_delay_ms(300); Resolution = 6500; //8000 }else{ //_delay_ms(400); Resolution = 3500; } //Resolution = 7000; flyMode = RAMPDOWN; ledOn(led); break; case RAMPDOWN: if(brightness <= 0 ){ brightness=1; // led++; flyMode = BLANK; } OCR0B=brightness; OCR0A=brightness; brightness--; _delay_us(100); break; case BLANK: ledOff(); // _delay_ms(1000); nextSleep++; if(nextSleep>4){ nextSleep=0; }
goToSleep(nextSleep); flyMode = INIT; Resolution = 2000; break; } }}
void initTimer0(void){ //Non inverting: TCCR0A = (1 << COM0A1) | (1 << WGM01); //Toggle OC0A and OC0B on compare match | (1 << COM0A0) | (1 << COM0B1) TCCR0B = (1<<CS01) | (1 << WGM02)| (1 << WGM03); //Clear on compare, use divide by 8 clock //mode:14 1110 Fast PWM ICR0 is top ICR0=Resolution; // OCR0A = 1500;}void initTimer1(void){ //Non inverting: TCCR0A = (1 << COM0B1) | (1 << WGM01); //Toggle OC0A and OC0B on compare match | (1 << COM0A0) | (1 << COM0B1) TCCR0B = (1<<CS01) | (1 << WGM02)| (1 << WGM03); //Clear on compare, use divide by 8 clock //mode:14 1110 Fast PWM ICR0 is top ICR0=Resolution; // OCR0B = 1500;}
void ledOn(uint8_t ledPort){ switch(ledPort){ case 0: DDRB = 0b0011; initTimer0(); //led=1; break; case 1: DDRB = 0b0011; initTimer1(); // led=2; break; case 2: DDRB = 0b0110; PORTB &= ~(1<<2); initTimer1(); // led=3; break; case 3: DDRB = 0b0101; PORTB &= ~(1<<2); initTimer0(); // led=0; break; //4 and 5 can both be set up as inverting or non inverting. I chose non, it looks cool. But then put it back case 4: DDRB = 0b0101; PORTB |= (1<<2); //inverting: TCCR0A = (1 << COM0A1) | (1 << COM0A0) | (1 << WGM01); //Toggle OC0A and OC0B on compare match | (1 << COM0A0) TCCR0B = (1<<CS01) | (1 << WGM02)| (1 << WGM03); //Clear on compare, use unscaled clock ICR0=Resolution; break;
case 5: DDRB = 0b0110; PORTB |= (1<<2); //inverting: TCCR0A = (1 << COM0B1) | (1 << COM0B0) | (1 << WGM01); //Toggle OC0A and OC0B on compare match | (1 << COM0B0) TCCR0B = (1<<CS01) | (1 << WGM02)| (1 << WGM03); //Clear on compare, use unscaled clock ICR0=Resolution; break;
}}
void ledOff(){ PORTB = 0; DDRB = 0; TCCR0A = 0; TCCR0B = 0;}
void goToSleep(uint8_t sleepTime){ 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 - if you don't add this, it will not restart. //__asm__ __volatile__("sleep") ; //enter sleep, waiting for interrupt -- This worked great!!! //below line is wrong. should be 0b01100000 because its a reserved number not a valid time hence sleeping 4 seconds. //CCP = 0xd8; Unknown if needed 20230630 switch (sleepTime){ /*case 0: WDTCSR = 0b01000010; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break;*/ case 0: WDTCSR = 0b01000011; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break; case 1: WDTCSR = 0b01000110; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break; case 2: WDTCSR = 0b01100001; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break; case 3: WDTCSR = 0b01100000; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break; case 4: WDTCSR = 0b01000111; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? break; }// WDTCSR = 0b01000111; //1000 4 sec 0111 2 sec -- sherm recheck this line!! why 16ms? __asm__ __volatile__ ( "sleep" "\n\t" :: ); //Sleep instruction to put controller to sleep (found this syntax)}