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();
}
}



