#include #include #include #include #define DUTY 15 #define LED_PIN PB0 //#define ONTIME 7210 //#define OFFTIME 10094 //#define ONTIME 213 //#define OFFTIME 425 #define ONTIME 1 #define OFFTIME 1 #define BODS 7 //BOD Sleep bit in MCUCR #define BODSE 2 //BOD Sleep enable bit in MCUCR #define N_1 (_BV(CS00)) #define N_8 (_BV(CS01)) #define N_64 (_BV(CS01) | _BV(CS00)) #define N_256 (_BV(CS02)) #define N_1024 (_BV(CS02) | _BV(CS00)) static void setPrescaler(uint8_t mode) { cli(); CLKPR = bit(CLKPCE); CLKPR = mode; sei(); } uint8_t onoff = 1; volatile uint16_t seccount = 0; volatile uint16_t lastsec = 0; uint8_t daycount = 0; static void pwm_init(void) { DDRB |= _BV(PB0); // set PWM pin as OUTPUT TCCR0A |= _BV(WGM01) | _BV(WGM00); // set timer mode to FAST PWM TCCR0A |= _BV(COM0A1); // connect PWM signal to pin (AC0A => PB0) } /* When timer is set to Fast PWM Mode, the freqency can be calculated using equation: F = F_CPU / (N * 256) Posible frequencies (@1.2MHz): -> F(N_1) = 4.687kHz -> F(N_8) = 585Hz -> F(N_64) = 73Hz -> F(N_256) = 18Hz -> F(N_1024) = 4Hz */ static void pwm_set_frequency(uint32_t N) { TCCR0B = (TCCR0B & ~((1 << CS02) | (1 << CS01) | (1 << CS00))) | N; // set prescaler } static void pwm_set_duty(uint8_t duty) { OCR0A = duty; // set the OCRnx } static void pwm_stop(void) { TCCR0B &= ~((1 << CS02) | (1 << CS01) | (1 << CS00)); // stop the timer } ISR(WDT_vect) { cli(); seccount++; // set prescaler to 5s and enable Watchdog Timer WDTCR |= (1 << WDCE); WDTCR = (1 << WDTIE) | (0 << WDE) | (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (0 << WDP0); sei(); // enable global interrupts if(!onoff && (seccount > OFFTIME)) { onoff=1; seccount=0; lastsec=0; pwm_set_frequency(N_8); pwm_init(); pwm_set_duty(DUTY); // goToSleep(true); return; } if(onoff && seccount > ONTIME){ onoff=0; seccount=0; lastsec=0; pwm_stop(); // goToSleep(false); } } void setup() { /* setup */ pinMode(LED_PIN, OUTPUT); setPrescaler(4); pwm_set_frequency(N_8); pwm_init(); pwm_set_duty(DUTY); onoff=1; seccount = 0; cli(); WDTCR |= (1 << WDCE); WDTCR = (1 << WDTIE) | (0 << WDE) | (1 << WDP3) | (0 << WDP2) | (0 << WDP1) | (0 << WDP0); sei(); // enable global interrupts } void goToSleep(bool withInterrupt) { byte adcsra, mcucr1, mcucr2; set_sleep_mode(SLEEP_MODE_IDLE); sleep_enable(); MCUCR &= ~(_BV(ISC01) | _BV(ISC00)); //INT0 on low level if(withInterrupt){ GIMSK |= _BV(INT0); //enable INT0 } adcsra = ADCSRA; //save ADCSRA ADCSRA &= ~_BV(ADEN); //disable ADC cli(); //stop interrupts to ensure the BOD timed sequence executes as required mcucr1 = MCUCR | _BV(BODS) | _BV(BODSE); //turn off the brown-out detector mcucr2 = mcucr1 & ~_BV(BODSE); //if the MCU does not have BOD disable capability, MCUCR = mcucr1; // this code has no effect MCUCR = mcucr2; sei(); //ensure interrupts enabled so we can wake up again sleep_cpu(); //go to sleep sleep_disable(); //wake up here ADCSRA = adcsra; //restore ADCSRA } void loop() { }