#include #include #include #include /* Pinout used: * ----- * !reset - MCU - Vcc * NA - MCU - NA * NA - MCU - NA * GND - MCU - (PB0) powerbutton * ----- */ static const uint8_t SLEPT_TIMEOUT = 25; /* ~2.5s */ static void init_timer() { /* timer_resolution = 1 / (clock_speed / prescaler) * timer_resolution = 1 / (10**6 / 1024) * * in ctc mode, target counts: * * timer_counts = (target_time / timer_resolution) - 1 * timer_counts = (0.1 / (1/(10**6/1024))) - 1 * timer_counts = 96.65625000000001 =~ 97 * * Why did we add the extra +1 to our number of timer counts? In CTC mode, * when the timer matches our desired count it will reset itself to zero. * This takes one clock cycle to perform, so we need to factor that into * our calculations. * * VG notes: more simply 0 to 97 = 98 values = 98 cycles. * * trigger_time = (97+1) * (1/(10**6 / 1024)) =~ 0.100352s * * WGM0[2:0] = 010 = CTC */ TCCR0A = (1 << WGM01) | // CTC (0 << WGM00); // CTC TCCR0B = (0 << WGM02) | // CTC (1 << CS02) | // CS0[2:0] = 101 => prescaler clk/1024 (0 << CS01) | // CS0[2:0] = 101 => prescaler clk/1024 (1 << CS00); // CS0[2:0] = 101 => prescaler clk/1024 OCR0A = 97; TIMSK = (1 << OCIE0A) | // enable CTC interrupt for compare match 0A (0 << OCIE0B) | // disable CTC interrupt for compare match 0B (0 << TOIE0); // disable interrupt for timer0 overflow } static volatile uint8_t sleep_time; ISR(TIMER0_COMPA_vect) { ++sleep_time; } static uint8_t get_sleep_time(void) { return sleep_time; } static void reset_sleep_time(void) { sleep_time = 0; } int main() { cli(); PORTB = 0; // outputs set to low and input not set to internal pull-up init_timer(); sei(); // Normally a loop is not required but if somehow the mcu woke up from its // sleep state this ensure we can do the operation again. for (;;) { reset_sleep_time(); // digital output, pull-down for a time then go to default PB0 = Hi-Z DDRB |= (1 << PB0); while (get_sleep_time() <= SLEPT_TIMEOUT); DDRB &= ~(1 << PB0); /* set low power mode */ power_all_disable(); // disable all peripherals set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode sleep_enable(); // set register to enable sleep sleep_bod_disable(); // disable bod to consume even less //sei(); // normally set sei to ensure wakeup but I do // not want to wake up appart from a power // reset sleep_cpu(); // put cpu to sleep = low power mode now sleep_disable(); // clear register (if somehow mcu woke up) } return 0; }