Source file: /~heha/mb-iwp/Kleinkram/Totenkopf.zip/Totenkopf.cpp

/*
Projekt: 3 Totenkopf-LEDs für Geburtstagsgeschenk an Enrico Gruber.

Hardware: ATtiny85 (liegt gerade herum und hat 3 PWM-fähige Ausgänge)
und 3 LEDs, hier H-aktiv, an den Augen (rot) und auf der Mütze (orange).

Mikrocontroller-Portpins (in Klammern nur für ISP-Funktion):
5 PB0	OC0A	(MOSI)	LED linke Augenhöhle
6 PB1	OC0B	(MISO)	LED rechte Augenhöhle
7 PB2	INT0	(SCK)	Ein-Taster
2 PB3	-		-
3 PB4	OC1B		LED Mütze
1 PB5		!RESET	-

Stromverbrauch:
* In Gebrauch ca. 5 mA für Mikrocontroller und LEDs
* 0,14 µA nach Timeout @ 3 V

Regime:
Diverse Muster werden auf die LEDs gegeben.
Der Watchdog-Timer wird für die Spiellänge herangezogen
und greift dadurch „zufällig“ in die feste Sequenz ein.
*/
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>

typedef unsigned char byte;

ISR(INT0_vect) {
 wdt_reset();
 GPIOR1 = 30;		// ≈ 30 s Action
}

ISR(WDT_vect) {
 if (!--GPIOR1) {
  WDTCR = 0x06;		// Watchdog anhalten
  DDRB  = 0;		// Keine Ausgänge
  MCUCR = 0x30;		// PowerDown, INT0 asynchron
  sei();
  sleep_cpu();		// Einzige Interruptquelle: Taster
  MCUCR = 0x22;		// Idle, INT0 bei fallender Flanke
  GIFR  = 0x40;
  DDRB  = 0x13;
  WDTCR = 0x46;
 }
}

ISR(TIMER0_OVF_vect) {
 ++GPIOR2;
}

// Timerüberläufe (2 ms) warten, 0 = 256 ≈ 0,5 s
static void delay(byte t) {
 do sleep_cpu(); while(--t);
}

int main() {
 PORTB = 0x04;
 DDRB  = 0x13;
 DIDR0 = 0x3B;		// Digital-Lesefunktion nur an PB2
 MCUCR = 0x22;		// Idle und INT0 bei fallender Flanke
 GIFR  = 0x40;
 GIMSK = 0x40;		// INT0 aktiv
 ACSR  = 0x80;
 TCCR0A= 0xA3;		// OC0A, OC0B: PWM nichtinvertierend
 TCCR0B= 0x02;		// PWM mit ≈ 500 Hz bei Vorteiler 8
 TIMSK = 0x02;		// Timer0-Überlauf = Interrupt = Zeitschritt für Programm
 TCCR1 = 0x84;		// Vorteiler 8, PWM-Modus
 GTCCR = 0x60;		// OC1B = nichtinvertierende PWM, !OC1B frei
 GPIOR1= 15;		// 15 s nach PowerOn (nach Taster länger)
 WDTCR = 0xDE;		// 1 s
 WDTCR = 0x46;		// Interrupt-Mode
 sei();
 for(;;){
// Programm 1: Wechselblinken, Kopf halbe Frequenz, 10 Zyklen
  byte z=10,t=0;
  OCR1B = 0;
  do{
   OCR1B =~OCR1B;	// oben an
   OCR0A = 0xFF;	// links an
   OCR0B = 0x00;	// rechts aus
   delay(0);	// 0,5 s
   OCR0A = 0x00;
   OCR0B = 0xFF;
   delay(0);	// 0,5 s
  }while (--z);
// Programm 2: Auf- und Abschwellen der Augen, wechselseitig
  z=10;
  do{
   OCR1B = 0x60;
   do{
    OCR0A = --t;	// links dunkler werdend
    OCR0B = ~t;		// rechts heller werdend
    sleep_cpu();	// 2 ms
   }while(t);
   OCR1B = 0x20;
   do{
    OCR0B = --t;	// rechts dunkler werdend
    OCR0A = ~t;		// links heller werdend
    sleep_cpu();	// 2 ms
   }while(t);
  }while (--z);
// Programm 3: Zwinkern (beide Augen)
  z=10;
  do{
   OCR1B = 0xE8;
   for (byte zz=0; zz<2; zz++) {
    OCR0A = OCR0B = 0xFF;
    delay(10);
    OCR0A = OCR0B = 0x00;
    delay(30);
   }
   do sleep_cpu(); while(--t);
   OCR1B-= 0x18;
  }while (--z);
 }
}
Detected encoding: UTF-80