main.c


1
/*
2
Darstellung einer Wort-Uhr auf der Hardware des Retro-PONG-Spiels 
3
4
Version vom 4.11.2011
5
6
7
Realisiert mit ATmega8 an 4.096MHz Quarz
8
9
Keine Bedienelemente - die Uhr empfängt DCF-77 Signale und stellt sich selbst.
10
11
12
Angezeigt wird eine interne Uhr, die vom DCF-Empfang bei korrektem Empfang minütlich gestellt wird.
13
Die Flanke jedes Sekundensignals wird zur Feinjustierung der hunderstel Sekunden benutzt.
14
Ohne Empfang läuft die interne Uhr mit der Zeit weg (Quarz zu ungenau). Das können schon mal 2 Minuten pro Tag sein.
15
16
Der DCF-77 Empfänger startet erst nach einer fallenden Flanke an seinem PON Eingang.
17
18
19
Da der Compiler/Optimizer leider ignoriert, dass eine Variable als volatile gekennzeichnet ist
20
und dann den Wert bei einem Vergleich nicht neu aus dem Speicher liest, benutze ich zur Übergabe eines Bits aus einer 
21
Interrupt-Routine einen Portpin. Der ist definitiv volatile - und das berücksichtigt der Compiler bisher immer.
22
Man kann daher an PD3 den 200Hz Takt abgreifen.
23
24
--- Anschluss Quarz ---
25
B6 und B7: 4096KHz Quarz    (Prozessorpin 7+8) 
26
27
--- Anschluss DCF-77-Empfänger ---
28
K1: GND
29
K2: +5V                   (PD2)
30
C4: output PowerOn DCF77  (PC4)
31
C5: input DCF77-Empfänger (PC5)
32
*/
33
#define F_CPU 4096000UL  /* CPU clock in Hertz */
34
35
#include <avr/io.h>
36
#include <avr/interrupt.h>
37
#include <util/delay.h>
38
39
40
//Potenzen von 2
41
#define BIT0 1
42
#define BIT1 2
43
#define BIT2 4
44
#define BIT3 8
45
#define BIT4 16
46
#define BIT5 32
47
#define BIT6 64
48
#define BIT7 128
49
#define BIT8 256
50
#define BIT9 512
51
#define BIT10 1024
52
#define BIT11 2048
53
54
//Standard Datentypen
55
#define U8  unsigned char
56
#define U16 unsigned int
57
#define U32 unsigned long
58
#define I16 int
59
60
//I/O Makros DCF77-Empfänger
61
#define   DI_DCF77_BIT (PINC & BIT5)
62
#define   DO_DCF_ENABLE (PORTC &=~ BIT4)
63
#define   DO_DCF_DISABLE (PORTC |= BIT4)
64
#define   DO_DCF_POWERSUPPLY (PORTD |= BIT2)
65
66
//I/O Makros Spaltentreiber (Shift&Store Schieberegister CD4094)
67
#define    DO_DATA_H    (PORTB |=  BIT4)
68
#define    DO_DATA_L    (PORTB &= ~BIT4)
69
#define    DO_CLK_H    (PORTB |=  BIT3)
70
#define    DO_CLK_L    (PORTB &= ~BIT3)
71
#define    DO_STROBE_H  (PORTB |=  BIT2)
72
#define    DO_STROBE_L  (PORTB &= ~BIT2)
73
74
75
76
/* DCF-77 Decoder */
77
/*
78
Während jeder Minute werden die Nummern von Minute, Stunde, Tag, Wochentag, 
79
Monat und Jahr BCD-kodiert durch Impulsmodulation der Sekundenmarken übertragen. 
80
Dieses "Telegramm" gilt jeweils für die folgende Minute. 
81
Dabei entsprechen Sekundenmarken mit einer Dauer von 0,1 s der binären Null 
82
und solche mit einer Dauer von 0,2 s der binären Eins. Die Zuordnung der einzelnen 
83
Sekundenmarken auf die übertragene Zeitinformation zeigt das Kodierschema 
84
85
86
0.              Minutenbeginn (immer LOW)
87
1. - 14.        Reserviert, keine Bedeutung (neuedings: Verschlüselte Wetterdaten)
88
15.             Reserveantenne aktiv
89
16.             Umstellung von Sommer- auf Winterzeit, oder umgekehrt
90
17.             Sommerzeit aktiv
91
18.             Winterzeit aktiv
92
19.             Ankündigung Schaltsekunde
93
20.             Zeitbeginn (Immer High)
94
21. - 27.       Minute 1, 2, 4, 8, 10, 20, 40
95
28.             Prüfbit Minute
96
29. - 34.       Stunde 1, 2, 4, 8, 10, 20
97
35.             Prüfbit Stunde
98
36. - 41.       Tag 1, 2, 4, 8, 10, 20
99
42. - 44.       Wochentag 1, 2, 4
100
45. - 49.       Monat 1, 2, 4, 8, 10
101
50. - 57.       Jahr 1, 2, 4, 8, 10, 20, 40, 80
102
58.             Prüfbit Datum
103
59.             fehlt zur Erkennung des Minutenanfangs
104
105
Die drei __Prüfbits__ P1, P2 und P3 ergänzen jeweils die vorhergehenden Informationswörter 
106
(7 Bits für die Minute, 6 Bits für die Stunden und 22 Bits für das Datum, einschließlich 
107
der Nummer des Wochentages) auf eine __gerade__ Anzahl von Einsen.
108
109
Die Zeitmarken Nr. 17 und 18 zeigen an, auf welches Zeitsystem sich die ausgesandte 
110
Zeitinformation bezieht. Bei Aussendung der MEZ wird die Sekundenmarke Nr. 18 auf 0,2 s
111
verlängert; die Sekundenmarke Nr. 17 hat eine Dauer von 0,1 s. Bei der Aussendung der 
112
MESZ ist es umgekehrt.
113
114
Vor einem Übergang von MEZ nach MESZ oder zurück wird außerdem jeweils eine Stunde 
115
lang die Sekundenmarke Nr. 16 als verlängerte Marke (0,2 s) ausgesendet. Diese 
116
Verlängerung beginnt beim Übergang von MEZ auf MESZ (von MESZ nach MEZ) um 
117
01.00.16 Uhr MEZ (2.00.16 Uhr MESZ) und endet um 01.59.16 Uhr MEZ (02.59.16 Uhr MESZ).
118
119
Die Sekundenmarke Nr. 19 kündigt eine Schaltsekunde an. Sie wird dann ebenfalls 
120
eine Stunde lang vor Einführung der Schaltsekunde als verlängerte Marke (0,2 s) 
121
ausgesendet. Schaltsekunden werden weltweit zum gleichen Zeitpunkt in die koordinierte 
122
Weltzeitskala UTC eingeführt, vorzugsweise am Ende der letzen Stunde des 31. Dezember 
123
oder des 30. Juni. Dies bedeutet, daß Schaltsekunden in der gesetzlichen Zeit der 
124
Bundesrepublik Deutschland eine Sekunde vor 1 Uhr MEZ am 1. Januar oder vor 
125
2 Uhr MESZ am 1. Juli eingeschoben werden. Bei einer Schaltsekunde am 1. Januar (1. Juli)
126
beginnt daher die Verlängerung der Sekundenmarke Nr. 19 um 00.00.19 Uhr MEZ (01.00.19 Uhr MESZ)
127
und endet um 00.59.19 Uhr MEZ (01.59.19 Uhr MESZ).
128
129
Beim Einfügen einer Schaltsekunde hat die zugehörige Minute eine Dauer von 61 Sekunden,
130
und die der Marke 01.00.00 Uhr MEZ (02.00.00 Uhr MESZ) vorhergehende 59. Sekundenmarke 
131
wird mit einer Dauer von 0,1 s ausgesendet. Die zur eingefügten 60. Sekunde gehörige 
132
Marke wird weggelassen (keine Trägerabsenkung).
133
134
*/
135
136
//------------------------------------------------------------------------------
137
138
//Globale Variable
139
typedef struct {
140
  U8  zeitUebernehmen;
141
  U8  bBit[60];      //die empfangenen Bits
142
  U8  erfolgreichdecodiert;
143
  U8  stoerung;      //Unplausibler Empfang
144
  U8  zeitEmpfangen; //Schaltet auf Zeitanzeige statt Sekundenanzeige um
145
146
147
  U8  uhrHH;  //Die interne Uhr (wird von DCF-Uhr gestellt)
148
  U8  uhrMM;
149
  U8  uhrSS;
150
  U8  dcfSekunde; //0..59 - wird bei ausbleibendem Signal (59. Sekunde) auf 0 gesetzt
151
152
  U8  vorHH; //Die empfangene Zeit in der letzten Minute
153
  U8  vorMM;
154
  U8  vorJJ;
155
}Tglob;
156
157
Tglob volatile g;
158
U16    spalte[12];
159
160
//------------------------------------------------------------------------------
161
162
// Texte im Display
163
#define Z1 1
164
#define Z2 2
165
#define Z3 4
166
#define Z4 8
167
#define Z5 16
168
#define Z6 32
169
#define Z7 64
170
#define Z8 128
171
#define Z9 256
172
#define ZA 512
173
174
#define    TEXT_ES_IST      spalte[0]|=Z1; spalte[1]|=Z1; spalte[3]|=Z1; spalte[4]|=Z1; spalte[5]|=Z1
175
#define    TEXT_FUENF1      spalte[7]|=Z1; spalte[8]|=Z1; spalte[9]|=Z1; spalte[10]|=Z1
176
177
#define    TEXT_ZEHN1      spalte[0]|=Z2; spalte[1]|=Z2; spalte[2]|=Z2; spalte[3]|=Z2
178
#define    TEXT_ZWANZIG    spalte[4]|=Z2; spalte[5]|=Z2; spalte[6]|=Z2; spalte[7]|=Z2; spalte[8]|=Z2; spalte[9]|=Z2; spalte[10]|=Z2
179
180
#define    TEXT_DREI1      spalte[0]|=Z3; spalte[1]|=Z3; spalte[2]|=Z3; spalte[3]|=Z3
181
#define    TEXT_VIERTEL    spalte[4]|=Z3; spalte[5]|=Z3; spalte[6]|=Z3; spalte[7]|=Z3; spalte[8]|=Z3; spalte[9]|=Z3; spalte[10]|=Z3
182
183
#define    TEXT_NACH        spalte[2]|=Z4; spalte[3]|=Z4; spalte[4]|=Z4; spalte[5]|=Z4
184
#define    TEXT_VOR        spalte[6]|=Z4; spalte[7]|=Z4; spalte[8]|=Z4
185
186
#define    TEXT_HALB        spalte[0]|=Z5; spalte[1]|=Z5; spalte[2]|=Z5; spalte[3]|=Z5
187
#define    TEXT_ZWOELF      spalte[5]|=Z5; spalte[6]|=Z5; spalte[7]|=Z5; spalte[8]|=Z5; spalte[9]|=Z5
188
189
#define    TEXT_ZWEI        spalte[0]|=Z6; spalte[1]|=Z6; spalte[2]|=Z6; spalte[3]|=Z6
190
#define    TEXT_EIN        spalte[2]|=Z6; spalte[3]|=Z6; spalte[4]|=Z6
191
#define    TEXT_EINS        spalte[2]|=Z6; spalte[3]|=Z6; spalte[4]|=Z6; spalte[5]|=Z6; 
192
#define    TEXT_SIEBEN      spalte[5]|=Z6; spalte[6]|=Z6; spalte[7]|=Z6; spalte[8]|=Z6; spalte[9]|=Z6; spalte[10]|=Z6
193
194
#define    TEXT_DREI        spalte[1]|=Z7; spalte[2]|=Z7; spalte[3]|=Z7; spalte[4]|=Z7 
195
#define    TEXT_FUENF      spalte[7]|=Z7; spalte[8]|=Z7; spalte[9]|=Z7; spalte[10]|=Z7
196
197
#define    TEXT_ELF        spalte[0]|=Z8; spalte[1]|=Z8; spalte[2]|=Z8
198
#define    TEXT_NEUN       spalte[3]|=Z8; spalte[4]|=Z8; spalte[5]|=Z8; spalte[6]|=Z8
199
#define    TEXT_VIER        spalte[7]|=Z8; spalte[8]|=Z8; spalte[9]|=Z8; spalte[10]|=Z8
200
201
#define    TEXT_ACHT        spalte[1]|=Z9; spalte[2]|=Z9; spalte[3]|=Z9; spalte[4]|=Z9
202
#define    TEXT_ZEHN       spalte[5]|=Z9; spalte[6]|=Z9; spalte[7]|=Z9; spalte[8]|=Z9;
203
204
#define    TEXT_SECHS      spalte[1]|=ZA; spalte[2]|=ZA; spalte[3]|=ZA; spalte[4]|=ZA; spalte[5]|=ZA
205
#define    TEXT_UHR        spalte[8]|=ZA; spalte[9]|=ZA; spalte[10]|=ZA
206
207
208
//  12345 12345 12345 12345 12345 12345 12345 12345 12345 12345 
209
//1   §    §§§   §§§     §  §§§§§   §§  §§§§§  §§§   §§§   §§§  
210
//2  §§   §   § §   §   §§  §      §        § §   § §   § §   § 
211
//3   §       §     §  § §  §§§§  §        §  §   § §   § §   § 
212
//4   §      §    §§  §  §      § §§§§    §    §§§   §§§§ §   § 
213
//5   §     §       § §§§§§     § §   §  §    §   §     § §   § 
214
//6   §    §    §   §    §  §   § §   §  §    §   §     § §   § 
215
//7  §§§  §§§§§  §§§     §   §§§   §§§   §     §§§   §§§   §§§  
216
//
217
218
219
const U8 ziffern[10][5] =         // Die 10 Ziffern in 5 Spalten und 7 Zeilen darstellen 
220
{//   1           2             3                    4                      5
221
  {Z2|Z3|Z4|Z5|Z6,  Z1|Z7,       Z1|Z7,                Z1|Z7,                Z2|Z3|Z4|Z5|Z6 },    // 0
222
  {0,               Z2|Z7,       Z1|Z2|Z3|Z4|Z5|Z6|Z7, Z7,                   0              },    // 1
223
  {Z2|Z7,           Z1|Z6|Z7,    Z1|Z5|Z7,             Z1|Z4|Z7,             Z2|Z3|Z7       },    // 2
224
  {Z2|Z6,           Z1|Z7,       Z1|Z4|Z7,             Z1|Z4|Z7,             Z2|Z3|Z5|Z6    },    // 3
225
  {Z4|Z5,           Z3|Z5,       Z2|Z5,                Z1|Z2|Z3|Z4|Z5|Z6|Z7, Z5             },    // 4
226
  {Z1|Z2|Z3|Z6,     Z1|Z3|Z7,    Z1|Z3|Z7,             Z1|Z3|Z7,             Z1|Z4|Z5|Z6    },    // 5
227
  {Z3|Z4|Z5|Z6,     Z2|Z5|Z7,    Z1|Z4|Z7,             Z1|Z4|Z7,             Z5|Z6          },    // 6
228
  {Z1,              Z1|Z5|Z6|Z7, Z1|Z4,                Z1|Z3,                Z1|Z2          },    // 7
229
  {Z2|Z3|Z5|Z6,     Z1|Z4|Z7,    Z1|Z4|Z7,             Z1|Z4|Z7,             Z2|Z3|Z5|Z6    },    // 8
230
  {Z2|Z3,           Z1|Z4|Z7,    Z1|Z4|Z7,             Z1|Z4|Z7,             Z2|Z3|Z4|Z5|Z6 }    // 9
231
}; 
232
233
234
//------------------------------------------------------------------------------
235
void anzeigen(void){  // Zeit auf spaltes ausgeben (wird jede Sekunde aufgerufen)
236
//------------------------------------------------------------------------------
237
  U8  i,h,z,e;
238
239
  //Bildschirm löschen
240
  for (i=0; i<12; spalte[i++]=0); 
241
242
  if(g.zeitEmpfangen){
243
    TEXT_ES_IST;
244
    if(     g.uhrMM <  5){TEXT_UHR;                              }
245
    else if(g.uhrMM < 10){TEXT_FUENF1;  TEXT_NACH;               }
246
    else if(g.uhrMM < 15){TEXT_ZEHN1;   TEXT_NACH;               }
247
    else if(g.uhrMM < 20){TEXT_VIERTEL; TEXT_NACH;               }
248
    else if(g.uhrMM < 25){TEXT_ZWANZIG; TEXT_NACH;              }
249
    else if(g.uhrMM < 30){TEXT_FUENF1;  TEXT_VOR;    TEXT_HALB;  }
250
    else if(g.uhrMM < 35){TEXT_HALB;                            }
251
    else if(g.uhrMM < 40){TEXT_FUENF1;   TEXT_NACH;    TEXT_HALB;  }
252
    else if(g.uhrMM < 45){TEXT_ZWANZIG; TEXT_VOR;               }
253
    else if(g.uhrMM < 50){TEXT_VIERTEL; TEXT_VOR;                             }
254
    else if(g.uhrMM < 55){TEXT_ZEHN1;    TEXT_VOR;                }
255
    else if(g.uhrMM < 60){TEXT_FUENF1;   TEXT_VOR;                }
256
257
    h = g.uhrHH;
258
    if(g.uhrMM >=25) h++;
259
    
260
    switch(h%12){
261
      case  0: TEXT_ZWOELF; break;
262
      case  1: if (g.uhrMM < 5) {
263
                TEXT_EIN;
264
              }else{ 
265
                TEXT_EINS;
266
              } break;
267
      case  2: TEXT_ZWEI; break;
268
      case  3: TEXT_DREI; break;
269
      case  4: TEXT_VIER; break;
270
      case  5: TEXT_FUENF; break;
271
      case  6: TEXT_SECHS; break;
272
      case  7: TEXT_SIEBEN; break;
273
      case  8: TEXT_ACHT; break;
274
      case  9: TEXT_NEUN; break;
275
      case 10: TEXT_ZEHN; break;
276
      case 11: TEXT_ELF; break;
277
    }
278
     ;
279
    //Minuten mit 4 Pixeln am rechten Rand 
280
    switch(g.uhrMM % 5){
281
      case 4: spalte[11]|=BIT6; //absichtlich kein BREAK!
282
      case 3: spalte[11]|=BIT5; 
283
      case 2: spalte[11]|=BIT4; 
284
      case 1: spalte[11]|=BIT3; 
285
    }
286
287
288
  }else{ //Noch keine DCF-Zeit vorhanden. Zeige Sekunden.
289
    z = (g.dcfSekunde / 10);
290
    e = (g.dcfSekunde % 10);
291
    for (i=0; i<5; i++){
292
      spalte[i] = ziffern[z][i];
293
      spalte[i+6] = ziffern[e][i];
294
    }
295
  }
296
}
297
298
299
//------------------------------------------------------------------------------
300
ISR(TIMER1_COMPA_vect) { // spalte-Multiplexing (1882Hz)
301
//------------------------------------------------------------------------------
302
static U8  x;
303
static U16 scope=0; //12 Bit Speicher für Mini-Oszilloskop
304
static U8 us531=0;  //Zählt alle 531µs hoch
305
U16 y;
306
307
  //Low side: Eine einzelne 0 durchschieben (mit CLK) und jeweils mit STROBE aktivieren
308
  x++;
309
  if(x > 11){
310
    x=0;
311
    DO_DATA_L;
312
  }else{
313
    DO_DATA_H;
314
  }
315
  //Delays, um den  CD4094 nicht an seiner Grenze zu betreiben
316
  _delay_us(2); //Warte, bis Daten stabil anliegen 
317
  DO_CLK_H; //Einen weiter schieben
318
  _delay_us(2);
319
  DO_CLK_L;
320
321
  //Zeilentreiber löschen
322
  PORTC &= ~0x0F;
323
  PORTD &= ~0xF0;
324
  PORTB &= ~0x03;
325
326
  //Spalte aktivieren (Low side)
327
  DO_STROBE_H; 
328
  DO_STROBE_L;
329
330
  //Spalte ausgeben (High side)
331
  y = spalte[x]; //10 Zeilentreiber, 12 Spalten
332
  //Solange noch keine Zeit empfangen: DCF-Signal in unteren beiden Zeilen anzeigen
333
  if (!g.zeitEmpfangen){  //Mini-Oszilloskop (simpler t-Y Schreiber ohne Trigger)
334
    us531++;
335
    if (us531 > 46){ //25ms sind rum
336
      us531=0;
337
      scope >>=1;//Pixel weiterschieben
338
    }  
339
    if (DI_DCF77_BIT){
340
      scope|=BIT11;  
341
    }else{ 
342
      scope&=~BIT11;
343
    }
344
    if (scope & (1<<x)){
345
      PORTB |=1;
346
    }else{
347
      PORTB |=2;
348
    }
349
  }else{
350
    PORTB |= (y >> 8) & 0x03; //2Bit
351
  }
352
353
  PORTC |= y & 0x0F;        //4Bit
354
  PORTD |= y & 0xF0;        //4Bit
355
}
356
357
358
#if 0
359
//------------------------------------------------------------------------------
360
ISR(TIMER2_COMP_vect){ // 5ms Takt
361
//------------------------------------------------------------------------------
362
  PORTD|=BIT3; //volatile Übergabe an main()
363
}
364
365
#else //Das Ganze handoptimiert in Assembler, da Verzögerungen das Multiplexing stören könnten.
366
void __attribute__ ((naked)) TIMER2_COMP_vect(void){ 
367
   asm("sbi  0x12, 3");   // High auf PD3 ausgeben
368
   asm("reti");
369
}
370
#endif
371
372
373
374
375
//------------------------------------------------------------------------------
376
//    MAIN
377
//------------------------------------------------------------------------------
378
int main(void)
379
{
380
static I16 iTic;        //ms seit letztem Absenkungsbeginn
381
382
static U8 bSteigend;    //TRUE: Tiefpass bewegt sich von 0 aufwärts (Nahe Sekundenanfang)
383
static I16 iTiefpass;
384
static U8 startphase=1; 
385
static U8 toggle;
386
static U8 hh,mm,ss;
387
static I16 hs;
388
  
389
static U8 tag, wtag, monat, jahr;
390
static U8 neuesDatum=0;
391
static U8 keinEmpfang;    //Zeit ohne korrekten Empfang in Minuten 
392
static U8 zeitumstellung; //Wird bei gesetztem DCF-Bit 16 hochgezählt
393
static U8 sommerzeit;     //Wird bei gesetztem DCF-Bit 17 hochgezählt
394
static U8 winterzeit;     //Wird bei gesetztem DCF-Bit 18 hochgezählt
395
U8 pulsdauer;
396
397
U8 bChecksum;
398
U8 i;
399
U8 *ram;
400
401
  cli();
402
   DDRC = BIT0|BIT1|BIT2|BIT3|BIT4;
403
  DDRD = BIT0|     BIT2|BIT3|BIT4|BIT5|BIT6|BIT7;
404
  DDRB = BIT0|BIT1|BIT2|BIT3|BIT4; 
405
  SFIOR &= (1<<PUD); //no Pullups
406
  
407
  PORTB=0;
408
  PORTC=0;
409
  PORTD=0;
410
411
   //Watchdog
412
  asm("wdr");
413
  WDTCR |= (1<<WDCE) | (1<<WDE);
414
  WDTCR=(1<<WDE) | (1<<WDP2) | (1<<WDP1)| (1<<WDP0); //Watchdog auf 2
415
  asm("wdr");
416
417
418
  DO_DCF_POWERSUPPLY;  //Saft auf DCF-Empfänger
419
  DO_DCF_DISABLE;
420
  //Takt: 4.096MHz
421
422
  // Timer 0 unbenutzt
423
  
424
  // Timer 1  für spalte-Multiplexing 
425
  TCCR1A = 0;
426
  TCCR1B = (1<<WGM12) | (1<<CS11) | (1<<CS10); //Teiler 64 -> 64000Hz       
427
  OCR1A = 33; //Gibt 1882Hz Interruptfrequenz. Das erzeugt 156 Bilder/s
428
  //DCF77 sendet bei 77,5KHz. Die Multiplex-Frequenz sollte möglichst kein ganzzahliger Teiler davon sein
429
  //  77500/1882=41,17 - krumm genug
430
  
431
432
  // Timer 2: 5ms DCF-77-Empfang Takt
433
  TCCR2  = (1<<WGM21)|(1<<CS22)|(1<<CS21) |(1<<CS20);      //CTC Mode,  Teiler 1024 -> 4KHz
434
  OCR2 = 19; //Gibt 200Hz Interruptfrequenz
435
  
436
  // Timer Interrupts
437
  TIMSK  = (1<<OCIE1A) | (1<<OCIE2); 
438
439
440
   //Globale Variablen mit Null initialisieren
441
  ram=(U8  *)&g;
442
  for (i=0; i< sizeof(Tglob); ram[i++]=0);
443
444
  //Warte, bis Spannungsversorgung des DCF-77-Empfänger stabil
445
  asm("wdr");
446
  _delay_ms(1000);
447
  asm("wdr");
448
  DO_DCF_ENABLE; //Fallende Flanke auf PON startet den Empfänger
449
450
  spalte[0]=Z1|ZA;
451
  spalte[11]=Z1|ZA;
452
   sei();  // Interrupt ein - die Show beginnt  
453
454
  while(1){
455
    asm("wdr");
456
457
    if (!(PORTD & BIT3)) continue; //Sync auf 5ms Takt
458
    PORTD &= ~BIT3;
459
460
    
461
    iTic+=5;  //5ms sind rum
462
    if (iTic>3000){ //Kein Signal
463
      iTic=3000;
464
    }
465
    //Eingang abfragen und filtern
466
    if (DI_DCF77_BIT){ //Signalabsenkung liefert High für 100ms oder 200ms
467
      iTiefpass+=5;
468
      if (iTiefpass>200) iTiefpass=200;  //auf 200ms begrenzen
469
    }else{
470
      iTiefpass-=5;
471
      if (iTiefpass<0){
472
        iTiefpass=0;
473
        bSteigend=1;
474
      }
475
    }
476
477
478
    //Minutenanfang erkennen
479
    if (iTic > 1500){ //Minutensignal: mehr als 1s keine Absenkung
480
      g.dcfSekunde=59;
481
    }
482
    else
483
    //Signallänge bestimmen und im Bitfeld eintragen
484
    if (160==iTic){ //160ms  Tiefpass ist entweder +100-60=40 oder +100+60=160
485
      pulsdauer=iTiefpass;
486
      if (iTiefpass > 90){      
487
        g.bBit[g.dcfSekunde]=1;
488
      }else{
489
        g.bBit[g.dcfSekunde]=0;
490
      }
491
    
492
      if ((iTiefpass < 5) ||   ((iTiefpass > 60) && (iTiefpass <100))){ //Unplausible Signaldauer
493
        if (g.stoerung <4) g.stoerung++;  
494
      }else{
495
        if (g.stoerung >0) g.stoerung--;  
496
      }
497
    }
498
    //Sekundenanfang erkennen
499
    if ((60==iTiefpass) && bSteigend){ //60ms seit Pulsbeginn
500
      bSteigend=0;
501
      iTic=60;
502
      g.dcfSekunde++;
503
      if (g.dcfSekunde>59){  //Jetzt ist Minutenanfang
504
        g.dcfSekunde=0;
505
        if (0==startphase){ //beim 1. Minutenanfang nach Einschalten ist die Zeit noch nicht übertragen
506
          g.zeitUebernehmen = 1;  
507
        }
508
509
        //Auswertung zum Minutenanfang
510
        if (g.zeitUebernehmen){
511
          if (g.bBit[16]){
512
            zeitumstellung++;
513
            }else{
514
            if (zeitumstellung) zeitumstellung--;
515
          }
516
          if (g.bBit[17]){
517
            if (sommerzeit < 60) sommerzeit++;
518
            }else{
519
            if (sommerzeit) sommerzeit--;
520
          }
521
          if (g.bBit[18]){
522
            if (winterzeit < 60) winterzeit++;
523
            }else{
524
            if (winterzeit) winterzeit--;
525
          }
526
          bChecksum=g.bBit[21]+g.bBit[22]+g.bBit[23]+g.bBit[24]+g.bBit[25]+g.bBit[26]+g.bBit[27]+g.bBit[28]; //Minute 
527
          if (0==(bChecksum % 2)){ //P1
528
            bChecksum=g.bBit[29]+g.bBit[30]+g.bBit[31]+g.bBit[32]+g.bBit[33]+g.bBit[34]+g.bBit[35];        //Stunde  
529
            if (0==(bChecksum % 2)){ //P2
530
              if (g.bBit[20]){ //Startbit; immer gesetzt
531
                bChecksum=0;
532
                for (i=36; i<59; i++){ //Checksumme über Datum 
533
                  bChecksum+=g.bBit[i];
534
                }
535
                if (0==(bChecksum % 2)){ //P3
536
                  neuesDatum=0;
537
                  keinEmpfang=0;
538
                  tag = g.bBit[36]+g.bBit[37]*2+g.bBit[38]*4+g.bBit[39]*8+g.bBit[40]*10+g.bBit[41]*20;
539
                  wtag = g.bBit[42]+g.bBit[43]*2+g.bBit[44]*4;
540
                  monat = g.bBit[45]+g.bBit[46]*2+g.bBit[47]*4+g.bBit[48]*8;
541
                  jahr = g.bBit[50]+g.bBit[51]*2+g.bBit[52]*4+g.bBit[53]*8+g.bBit[54]*10+g.bBit[55]*20+g.bBit[56]*40+g.bBit[57]*80;
542
                  if (g.zeitUebernehmen){
543
                    //Übernehme Zeit
544
                    g.zeitUebernehmen = 0;
545
                    hh = g.bBit[29]+g.bBit[30]*2+g.bBit[31]*4+g.bBit[32]*8+g.bBit[33]*10+g.bBit[34]*20;
546
                    mm = g.bBit[21]+g.bBit[22]*2+g.bBit[23]*4+g.bBit[24]*8+g.bBit[25]*10+g.bBit[26]*20+g.bBit[27]*40;
547
                    ss = 0;
548
                    //Ist diese Zeit genau eine Minute später als vor einer Minute? (zusätzliche Plausibilitätscheck)
549
                    g.vorMM++;
550
                    if (g.vorMM>59){
551
                      g.vorMM=0;
552
                      g.vorHH++;
553
                      if (g.vorHH >23) g.vorHH=0;
554
                    }
555
                    if ((g.vorHH == hh) 
556
                    && (g.vorMM == mm) 
557
                    && (g.vorJJ == jahr) //Beim Jahreswechsel muss die Uhr ja nicht um Mitternacht verdreht werden
558
                    && (jahr>10)){       //Wir haben 2011 - und mehr als 89 Jahre soll die Uhr gar nicht laufen
559
                      g.erfolgreichdecodiert=1;
560
                    }  
561
                    g.vorHH=hh;
562
                    g.vorMM=mm;
563
                    g.vorJJ=jahr; 
564
                  }
565
                }//P3
566
              }//Bit20
567
            }//P2
568
          }//P1
569
        }//g.zeitUebernehmen
570
        if (startphase) startphase--;
571
        for (i=0; i<60; i++){
572
          g.bBit[i]=0;
573
        }
574
      }//(g.dcfSekunde>59)
575
    
576
      //Interne Uhr feintunen
577
      //Hundertstel Sekunden g.hs sollte auf 6 stehen , wenn die Uhr richtig läuft (60ms seit steigender Flanke)
578
      //Nur machen, wenn Empfang OK
579
      if ((keinEmpfang < 2) && (0==g.stoerung)){
580
        if ((hs > 6) && (hs < 56)) {
581
          hs --; //Uhr etwas zurückdrehen
582
        }else{
583
          if (hs != 6){
584
            hs++; //Uhr etwas vor drehen. Überlauf wird weiter unten automatisch behandelt.
585
          }  
586
        }
587
      }
588
    }//Sekundenanfang (60ms)
589
590
    //Intere Uhr weiterdrehen
591
    toggle = !toggle;
592
    if (toggle){ //10ms sind rum
593
      hs++; //Hundertstel Sekunden
594
      if (hs>99){ //1s ist rum
595
        hs-=100; //Nicht auf 0 setzen, um Überlauf bei Uhr vordrehen (Feintuning) zu berücksichtigen
596
        g.uhrSS++;
597
        anzeigen();
598
        if (g.uhrSS > 59){
599
          g.uhrSS=0;
600
          g.uhrMM++;
601
          if (keinEmpfang < 100){ //Wird bei Empfang mit korreten Prüfsummen auf 0 gesetzt  
602
            keinEmpfang++;
603
          }  
604
          if (g.uhrMM > 59){
605
            g.uhrMM=0;
606
            g.uhrHH++;
607
            if (g.uhrHH > 23){
608
              g.uhrHH=0;
609
              neuesDatum=1; //Datum wird ja nicht angezeigt. Aber wenn ich das mal einbauen will, habe ich hiermit den Tagesbeginn.
610
            } 
611
            //Zeitumstellung?
612
            if ((zeitumstellung > 45) && (g.uhrHH >=2) && (g.uhrHH <=3)){ //"zeitumstellung" wurde in der Stunde vor der Umstellung jede Minute hochgezählt
613
              if (sommerzeit > winterzeit){ //MESZ->MEZ
614
                g.uhrHH--;
615
              }else{ //MEZ->MESZ
616
                g.uhrHH++;
617
              }
618
            }
619
          }//g.uhrMM>59
620
        }//g.uhrSS>59
621
        if (g.erfolgreichdecodiert){ //Zeit übernehmen (wenn vorhanden)
622
          g.erfolgreichdecodiert=0;
623
          g.zeitEmpfangen=1;
624
          g.uhrHH=hh;
625
          g.uhrMM=mm;
626
          g.uhrSS=0;
627
        }
628
629
      }//hs>99
630
    }//Toggle
631
  }//while 1
632
}
633
//EOF