Source file: /~heha/basteln/Haus/Telefon/CLIP-Anzeige/clip.zip/clip_ac-2.cpp

// CLIP für Analogvergleicher und Timer0
// Projekt Rufnummern-Anzeige

#include "ra.h"

static void terminate() {
#ifdef TIMSK0
 TIMSK0&=~0x06;
#else
 TIMSK&=~0x18;
#endif
 if (stat>=4 && cnt) stat=0xFF;
 else stat=0;
}

// Zählerwert Timer0 für 1200 Hz
#define T F_CPU/64/1200

// Flanke an Analogvergleicher
ISR(ANA_COMP_vect) {
 byte t=ACSRA;
 byte e=GPIOR0;
 if (!((t^e)&0x20)) return;	// Ohne Pegelwechsel an ACO ignorieren
 PINB|=4;
 t=TCNT0L-last;
 if (stat) {
  if (t<T/8) return;	// Zu kurz: Ignorieren
  GPIOR0=e^0x20;	// Nulldurchgang akzeptieren
  dif1=diff;
  diff=t;
 }
 last+=t;
 OCR0B=t+250;	// Zeitüberschreitung (zu tiefe Frequenz) feststellen lassen
 if (!stat) {
#ifdef TIMSK0
  TIFR0=0x04;
  TIMSK0|=0x04;
#else
  TIFR=0x08;
  TIMSK|=0x08;	// OCR0B aktivieren (für Timeout)
#endif
 }
 switch (stat) {
  case 0:	// Initialisierung: Erste Flanke
  cnt=akku=det=stat++;
  break;
  case 1: {	// Frequenzsuche: Trennschwelle zwischen hoch und tief
   add(akku,diff);
   adc0(det);	// 16-Bit-Zähler
   add(cnt,1);
   adc0(stat);	// 256 Flanken messen
  }break;
  case 2:	// Sicherstellen dass diese Trennschwelle auch stimmt
#if 0
  if (byte(det-32)<diff && diff<byte(det+32)) {
   add(cnt,16);
   adc0(stat);	// erfolgreich
  }else{
   cnt=0;
   --stat;	// weitersuchen
  }break;
#else
  ++stat;
#endif
  case 3:	// Suche dauerhaft tiefe Frequenz gegenüber Trennschwelle
  if (diff>=det) {
   add(cnt,16);
   adc0(stat);
  }else cnt=0;	// Frequenz zu hoch	// einige Nulldurchgänge lang
  break;
  case 4:	// Suche nach Startbit
  if (diff<det && dif1<det) {
   ++stat;
   t+=T-20-dif1-diff;	// ausprobiert: Zeit des „wahren“ Startbits
   OCR0A=t;	// Das „wahre Startbit“ kommt zu jener Zeit, wird ignoriert
#ifdef TIMSK0
   TIFR0=0x02;	// Anhängigen Interrupt löschen
   TIMSK0|=0x02;	// Beide Compare-Interrupts freigeben
#else
   TIFR=0x10;
   TIMSK|=0x10;	// OCR0A aktivieren
#endif
  }break;
 }
}

#define TOL 0

static bool bit() {
#if TOL==100
 return diff+dif1>=det+det;
#elif TOL
 return diff>det+TOL || diff>det-TOL && dif1>=det;
#else
 return diff>=det;
#endif
}

// Bitzeit, stat = 5..13
ISR(TIMER0_COMPA_vect) {
 akku>>=1;
 if (bit()) {
  akku|=0x80;	// Tiefe Frequenz = 1
 }
 sei();		// Ab hier darf der Pegelwechsel-Interrupt einschlagen
 switch (++stat) {
#if 0
  case 15: stat=5; OCR0A+=F_CPU/64/1200+3; break;
#else
  case 15: {	// Rahmenfehler detektieren
   if (!(akku&0x80) || cnt>=2 && cnt==clip.data[1]+3) terminate();
   stat=4;	// Startbit suchen lassen
#ifdef TIMSK0
   TIMSK0&=~0x02;
#else
   TIMSK&=~0x10;// OCR0A deaktivieren
#endif
  }break;
#endif
  case 14: switch (cnt) {
   case 0: if (akku!=0x80) terminate(); break;
   case 1: if (akku>elemof(clip.data)-3) terminate(); break;
  }
  clip.data[cnt++]=akku; nobreak; 	// Byte ablegen und weiter
  default: OCR0A+=T;	// = 208 @ 16 MHz für das nächste Bit
 }
}

// Zu lange auf Flanke gewartet (F_CPU/64/250 = 1 kHz @ 16 MHz, = 1 ms)
// Vor dem Signal kommt es erwartungsgemäß zu vielen dieser Interrupts
ISR(TIMER0_COMPB_vect) {
 terminate();
}

void CLIP::init() {
 TCCR0B= 0x02;	// F_CPU/8/8; T = 1,024 ms für F_CPU = 16 MHz
 ACSRA = 0x18;	// Analogvergleicher: Interruptfreigabe, beide Flanken
}
void CLIP::done() {
 ACSRA = 0x80;	// Interrupts aus
}
Detected encoding: UTF-80