1.05.2014

Mikro projekt timera ze stałym czasem 60 sekund i automatycznym restartem. Mikro-kontroler ATtiny13A zasilany baterią CR2032.


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