/* CLIP für Analogvergleicher und 8-Bit-Timer0
Projekt Rufnummern-Anzeige
Es ist für die korrekte Funktion extrem wichtig,
dass die beiden Analogvergleicher-Eingänge absolut symmetrisch
beschaltet sind. Im Experiment:
- Spannungsteiler 2× 10 kΩ von Ucc nach GND
(macht 0,25 mA zusätzlichen Querstrom: Besser abschaltbar gestalten!)
- Vom Mittelpunkt jeweils 1× 33 kΩ zu AIN0 und AIN1
- Koppelkondensatoren jeweils 1× 6,8 nF nach b-Ader (= Ucc) und a-Ader,
Zuordnung AIN0 / AIN1 egal.
Rechnerische Zeitkonstante: R×C = 0,22 ms , fg = 709 Hz
Der erste Ansatz verwendete nur 2 statt 4 Widerstände und nutzte
den integrierten Pullup bei einem der beiden AIN-Pins.
Dieses Konzept lief nur bei absolut glatter Betriebsspannung
vom Festspannungsregler einigermaßen brauchbar,
aber auch dann keineswegs so zuverlässig.
*/
#include "ra.h"
static void terminate() {
#ifdef TIMSK0
TIMSK0&=~0x06;
#else
TIMSK&=~0x18;
#endif
if (stat>=3 && cnt) stat=0xFF;
else stat=0;
}
// Zählerwert Timer0 für 1200 Hz (Baud)
#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
t=TCNT0L;
GPIOR0=e^0x20;
if (stat) {
dif1=diff;
diff=t-last;
if (diff<T/6) { // = 36 @ 16 MHz
terminate(); // Zu hohe Frequenz: Wieder vorn anfangen, nicht nur ignorieren
return;
}
}
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: // 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 3: // Suche nach Startbit
if (diff<det && dif1<det) {
++stat;
t+=T-20-dif1-diff; // = 150 @ 16 MHz
OCR0A=t; // Das erste Datenbit kommt zu jener Zeit
#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) {
case 14: { // Rahmenfehler detektieren
if (!(akku&0x80) || cnt>=2 && cnt==clip.data[1]+3) terminate();
stat=3; // Startbit suchen lassen
#ifdef TIMSK0
TIMSK0&=~0x02;
#else
TIMSK&=~0x10;// OCR0A deaktivieren
#endif
}break;
case 13: 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
TCCR0B= 0x05; // Standard-Vorteiler 1024
}
| Detected encoding: UTF-8 | 0
|