/*
Nach dem Anlegen der Versorgungsspannung gelangt der µC nach ein
paar Befehlen zur Initialisierung in den Power-Down-Modus mit einer Stromaufnahme
von <1µA und wartet auf einen Interrupt, der ihn aufweckt.

Wird beim Drücken des Tasters die Schaltschwelle von PB4 zum Erkennen eines '0'-Pegels überschritten, 
wird der PinChange-Interrupt ausgelöst. Der Kondensator wird in der PCINT-Routine 
beschleunigt entladen, bis er GND Potential erreicht hat. Dadurch wird die Eingangshysterese auf 
nahezu Vcc erhöht.
Das Drücken des Tasters invertiert fortlaufend das EIN_AUS_SIGNAL. Dies ist die einzige Funktion
des Programmes.

Das Loslassen des Tasters wird nicht ausgewertet. Lediglich der Kondensator am Eingang
wird aktiv auf '1' Pegel gebracht.

http://www.mino-elektronik.de

Alle Angaben ohne Gewaehr !
2013-03-29
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

#define BIT(x)	(1<<x)
#define EIN_AUS_TASTER	4	        // PortB 4
#define EIN_AUS_SIGNAL	3	        // PortB 3 (ggf. mit LED)

// Interrupt vom Ein-Aus-Taster
ISR (PCINT0_vect)
{
volatile uint8_t n = 0xff;	        // darf nicht wegoptimiert werden
  PCMSK &= ~BIT(EIN_AUS_TASTER);	// sperren
  if(PINB & BIT(EIN_AUS_TASTER)) {	// steigende flanke
    PORTB |= BIT(EIN_AUS_TASTER);
    DDRB  |= BIT(EIN_AUS_TASTER);	// und ausgang aktiv auf 1
  } else {
    PINB = BIT(EIN_AUS_SIGNAL); 	// bei jedem Tastendruck invertieren, mehr passiert nicht
    PORTB &= ~BIT(EIN_AUS_TASTER);
    DDRB  |= BIT(EIN_AUS_TASTER);	// und ausgang aktiv auf 0
  }
  while(n--); 			            // kurz warten bis kondensator aufge- oder entladen
  PORTB &= ~BIT(EIN_AUS_TASTER);    // pullup wegnehmen
  DDRB  &= ~BIT(EIN_AUS_TASTER);	// und auf Eingangschalten
  GIFR = 0x20;				        // ggf. Störungen ausfiltern, flag löschen
  PCMSK |= BIT(EIN_AUS_TASTER);		// zulassen
}

int16_t main(void)                  // typ. RC-Osz. 8MHz mit Teiler/8 
{
  DDRB  |= BIT(EIN_AUS_SIGNAL); 	// Schaltausgang (PB3) aktivieren
  PORTB |= BIT(EIN_AUS_SIGNAL); 	// und mit '1' anfangen
  PCMSK |= BIT(EIN_AUS_TASTER);	    // PCINT für PB4 freigeben
  GIFR = BIT(PCIF);		            // flag löschen
  GIMSK |= BIT(PCIE);		        // PCINT PORTB zulassen
  sei();

  while(1) {
      MCUCR = BIT(SE) + BIT(SM1);	// Power-Down wählen
      sleep_cpu();				    // und immer wieder schlafen legen
  }
}

