/* 
PULS-PAUSE-Timer per WDT vom ATtiny25/45/85

Beim Programmstart werden die beiden Ausgaenge POS_AUSGANG und NEG_AUSGANG 
für die Zeit PULS aktiviert. Hier sind es 6 Stunden.
Danach werden ca. 30 Tage gewartet, bis neue aktive Impuls ausgegeben werden. 
Die Genauigkeit des Timimgs liegt bei ca. 1-2 %.

Die Stromaufnahme betraegt etwa 7 µA @ 5 V.

Michael Nowak
www.mino-elektronik.de
2022-01-09
*/

#define nKURZZEITTEST

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define BIT(x)	(1<<x)
#define PRO_STUNDE    860UL									// Aufrufe des WDT pro Stunde bei 4 s
#define PRO_TAG       (PRO_STUNDE*24)
#define ANZAHL_TAGE   30

#define POS_AUSGANG  BIT(4)                 // PB4 
#define NEG_AUSGANG  BIT(3)                 // PB3
#define POS_NEG_MASKE (POS_AUSGANG | NEG_AUSGANG)   // Ausgaenge als Bitmuster

#ifndef KURZZEITTEST                        // normale Zeiten
#define PULS  (PRO_STUNDE * 6)              // fuer 6 Stunden
#define PAUSE (PRO_TAG * ANZAHL_TAGE)       // 30 Tage
#else
#define PULS  1                             // 4 Sekunden aktiv
#define PAUSE 2                             // 8 Sekunden Pause
#endif

// beim Programmstart mit Pulsdauer für aktive Ausgaenge beginnen
uint32_t wdt_cnt = PULS;                    // Abwaertszaehler für die WDT-Zeiten

// Aufwecken des µCs und Abzaehlen der Zeiten
// aktiver Impuls: POS_AUSGANG = 1 und NEG_AUSGANG = 0
ISR(WDT_vect) {                             // Aufruffrequenz ca. 0,25 Hz
  wdt_cnt--;    
  if(!wdt_cnt) {  // nach Ablauf der Zeit mit neuer Zeit starten und Ausgaenge umschalten                          
    if(!(PORTB & POS_AUSGANG))              // bei passiven Ausgaengen  
      wdt_cnt = PULS;                       // Zeit für Ausgangsimpuls laden
    else
      wdt_cnt = PAUSE;                      // ansonsten Pausenzeit einstellen
    PINB = POS_NEG_MASKE;                   // beide Ausgaenge umschalten
  } 
}    

int main(void)
{
  PORTB = 0xff;                   // Alle pullup-Widerstaende einschalten
  DDRB = POS_NEG_MASKE;           // Ausgaenge auf '1' setzen
  PINB = NEG_AUSGANG;             // NEG_AUSGANG auf '0'
  WDTCR = BIT(WDIE) | BIT(WDP3);  // Watchdog-Intervall auf 4 s per Interrupt
  sei();                          // ISR zulassen
  while(1) {
    MCUCR = BIT(SE) + BIT(SM1);   // Power-Down waehlen
    sleep_cpu();                  // und stoppen bis WDT aufweckt
  }
}