Timer służy do ciągłej pracy w pętli, odlicza 60 sekund i generuje dźwięk, następnie rozpoczyna odliczanie od nowa (funkcja wykorzystywana do odliczania czasu na ruch w grze). W czasie odliczania dodatkowo generowane są błyski co 1 sekundę- 20 błysków zielonych, następnie 20 czerwonych i przez ostatnie 20 sekund błyski niebieskie. Wciśnięcie przycisku START resetuje timer i rozpoczyna zliczanie od nowa (60s). Timer nie posiada przycisku odłączającego zasilanie, po uruchomieniu lub resecie wchodzi w tryb power-down i teoretycznie na baterii CR2032 (około 200mAh / <1uA) powinien spać przez 20 lat ( bateria tyle nie wytrzyma). Program ogranicza działanie timera do 60 minut. Jeżeli nie zostanie w tym czasie wciśnięty przycisk START program uzna, że timer nie jest już używany i procesor przejdzie w uśpienie power down aby nie wyczerpać baterii. Każde wciśnięcie przycisku START resetuje zliczanie i kolejne wyłączenie nastąpi po 60 minutach.
Zatrzymanie timera polega na fizycznym resecie procesora przyciskiem STOP, po ponownym uruchomieniu procesor automatycznie przejdzie w tryb power down z wyłączonym "watchdog" - prąd pobierany z baterii <1uA.
Rezystor ograniczający prąd diod został dobrany eksperymentalnie, dla 3V diody- zielona i czerwona obciążają baterię prądem 5 mA a niebieska około 1,5 mA. Ponieważ czas ich działania to 0,005 sekundy w ciągu jednej sekundy, średni pobór prądu wynosi 25 uA podczas działania timera. Buzer który został zastosowany teoretycznie powinien działać przy napięciu 5V, przy zasilaniu 3V przepływa przez niego 10 mA prądu. Czas jego działania to 150 ms na 60000 ms, średnio obciąża baterie prądem 25uA podczas działania timera. Procesor podczas działania timera jest budzony na około 5 ms, jego pobór prądu wynosi wtedy 300 uA (mierzone dla częstotliwości 600 kHz)- średnio daje to 1,5 uA. Przez 995 ms procesor śpi w trybie power-down z włączonym "watchdog"- mierzone obciążenie około 6 uA.
Sumarycznie średnie obciążenie baterii podczas działania timera wynosi około 60-70 uA, teoretycznie timer może pracować ciągle przez ponad 100 dni zasilany jedną baterią CR2032.
Schemat.
Całość została wykonana z elementów które aktualnie posiadałem, lutowanie na płytce uniwersalnej. Można wykorzystać jedną diodę RGB co zmniejszy ilość elementów.
Programowanie z wykorzystaniem standardowej podstawki.
Poniżej kod programu napisany w C w środowisku Eclipse.
/* * main.c * * Created on: 2014-01-05 * Autor: Tomasz Pliszczak */ /* * * Fuses = 69 FF * Frequency 600 000 Hz * */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/sleep.h> #include <avr/wdt.h> // def #define BUTTON (1<<PB1) #define LED_1 (1<<PB0) #define LED_2 (1<<PB2) #define LED_3 (1<<PB3) #define BUZZER (1<<PB4) volatile uint16_t minute, for_long, time_play; void WDT_on(void); void WDT_off(void); int main(void){ _delay_ms(500); // low power //turn off Analog Comparator ACSR |= (1<<ACD); //turn off ADC ADCSRA &= ~(1<<ADEN); // Use the Power Down sleep mode set_sleep_mode(SLEEP_MODE_PWR_DOWN); // int0 GIMSK |= (1<<INT0); GIFR |= (1<<INTF0); DDRB &= ~(BUTTON);// IN PORTB|=BUTTON; //VCC DDRB |= LED_1 | LED_2 | LED_3 | BUZZER; // out PORTB&=~( LED_1 | LED_2 | LED_3 | BUZZER); // all off // on start - 3x buzzer 100 ms for (int8_t i = 0; i < 3; ++i) { PORTB|=BUZZER; _delay_ms(100); PORTB&=~BUZZER; _delay_ms(200); } // Turn off WDT WDT_off(); time_play=60; // one countdown =60s sei(); while(1){ sleep_mode(); // power down <1uA } } //functions void WDT_on(void) { wdt_reset(); /* Clear WDRF in MCUSR */ MCUSR &= ~(1<<WDRF); WDTCR |= (1<<WDCE) | (1<<WDE); WDTCR |= (1 << WDP1) | (1 << WDP2) | (1 << WDTIE ) | (1<<WDE); // timer goes off every 1 seconds and interrupt wdt_reset(); /* Clear WDRF in MCUSR */ MCUSR &= ~(1<<WDRF); WDTCR |= (1<<WDCE) | (1<<WDE); WDTCR &= ~(1 << WDE ) ; // reset off } void WDT_off(void){ cli(); wdt_reset(); /* Clear WDRF in MCUSR */ MCUSR &= ~(1<<WDRF); WDTCR |= (1<<WDCE) | (1<<WDE); /* Turn off WDT */ WDTCR = 0x00; sei(); } // interrupts // INT0 after pushing the button ISR(INT0_vect) { minute=time_play; // play time for_long=3600; // stop counting after 3600 = 1h and go sleep WDT_on(); //WDT ON } // WDT ISR(WDT_vect) { //counter decrease minute--; for_long--; // blinking led (5ms) - 20x green, red, blue if( minute>(time_play-(time_play/3)-1)){ PORTB|=LED_1; _delay_ms(5); PORTB&=~LED_1; } else if (minute>((time_play/3)-1)) { PORTB|=LED_2; _delay_ms(5); PORTB&=~LED_2; } else { PORTB|=LED_3; _delay_ms(5); PORTB&=~LED_3; } // after one minute start again if(minute<1){ minute=time_play; // buzzer on PORTB|=BUZZER; _delay_ms(150); PORTB&=~BUZZER; } // after one hour - go to sleep if(for_long<1){ WDT_off(); } }