Forum: Mikrocontroller und Digitale Elektronik DCF Problem mit Code


von Jonas E. (jonas_e43)


Lesenswert?

Hallo,
Ich bin gerade dabei eine LCD Uhr auf Atmega32 Basis zu programmieren.
Ich habe das Forum bereits durchsucht. Jedoch funktionieren die Codes 
mit meinem Setup nicht bzw. sind zu komplex, als dass ich sie 
umschreiben könnte.

Habt ihr vielleicht etwas Beispielcode oder eine Library, den/die ich 
verwenden könnte? Das DCF Modul ist am INT0 Pin des Atmega angschlossen.

Gruß
Jonas

von ich (Gast)


Lesenswert?


von Jonas E. (jonas_e43)


Lesenswert?

So ich habe mal diesen Code für mein Projekt angepasst, um damit die DCF 
Zeit zu empfangen, nur leider wird wenn ich dcf_sync starte die ganze 
Main aufgehalten und der bildschirm flackert... Woran könnte das liegen?
1
//Header Dateien
2
#include <avr/interrupt.h>
3
#include "dcf_clock.h"
4
5
/////////////
6
//Variablen//
7
/////////////
8
//date
9
uint8_t week_day;
10
uint8_t day;
11
uint8_t month;
12
uint16_t year;
13
14
//time
15
uint16_t millisecond;
16
uint8_t second;
17
uint8_t minute;
18
uint8_t hour;
19
uint8_t timezone;
20
21
//Speicherbereich für DCF-Pegel
22
uint8_t dataPC;
23
24
//Pegel-Auswertung
25
uint16_t counter_high;
26
uint16_t counter_low;
27
uint8_t bit_number;
28
29
//dcf_date
30
uint8_t dcf_week_day;
31
uint8_t dcf_day;
32
uint8_t dcf_month;
33
uint8_t dcf_year;
34
uint8_t dcf_date_parity;
35
36
//dcf_time
37
uint8_t dcf_second;
38
uint8_t dcf_minute;
39
uint8_t dcf_minute_parity;
40
uint8_t dcf_hour;
41
uint8_t dcf_hour_parity;
42
uint8_t dcf_timezone;
43
44
//Puffer für die int --> char Umwandlung
45
char itoa_buffer[8];
46
47
//Array für die DCF-Datenbits
48
//uint8_t minute_frame[60];  //wird noch nicht genutzt
49
50
//Schaltjahr
51
uint8_t leapyear;
52
53
void initClock(void)
54
{
55
  //Setzen der Port-Richtungsregister
56
  DDRD &= ~(1<<PD2);  //PD2 Eingang (0)
57
  //Initialisieren der Ports
58
  //PORTD |= (1<<PD2);  //PD2 Pull-Up gesetzt (1)
59
60
  // Timer 1 konfigurieren
61
  TCCR1A = 0;
62
  TCCR1B |=(1<<WGM12)|(1<<CS12);
63
  OCR1A = 57;
64
  TIMSK |= (1<<OCIE1A);  //Compare Interrupt erlauben (1)
65
}
66
67
68
////////////////////
69
//Reset-Funktionen//
70
////////////////////
71
void counter_reset(void)
72
{
73
  counter_high=0;
74
  counter_low=0;
75
  bit_number=0;
76
}
77
78
void dcf_date_reset(void)
79
{
80
  dcf_week_day=0;
81
  dcf_day=0;
82
  dcf_month=0;
83
  dcf_year=0;
84
  dcf_date_parity=0;
85
}
86
87
void dcf_time_reset(void)
88
{
89
  dcf_minute=0;
90
  dcf_minute_parity=0;
91
  dcf_hour=0;
92
  dcf_hour_parity=0;
93
  dcf_timezone=0;
94
}
95
96
///////////////////////
97
//DCF-Synchronisation//
98
///////////////////////
99
//High-Pegel muß für 1700-1900ms anliegen
100
//Danach muß ein Low-Pegel folgen
101
void dcf_sync(void)
102
{
103
  if(!(dataPC & (1<<PIND2)))
104
  {
105
    if(counter_high>=1750 && counter_high<=1950)
106
    {
107
      
108
      counter_reset();
109
      dcf_date_reset();
110
      dcf_time_reset();
111
    }
112
    else
113
    {
114
      counter_high=0;
115
      dcf_sync();
116
    }
117
  }
118
  else
119
  {
120
    dcf_sync();
121
  }
122
}
123
124
//////////////////
125
//DCF-Auswertung//
126
//////////////////
127
void dcf_0(void)
128
{
129
  switch(bit_number)
130
  {
131
    case 0: ;break;  //Start einer neuen Minuten, muß immer 0 sein
132
    case 1: ;break;  //Wetterdaten
133
    case 2: ;break;  //Wetterdaten
134
    case 3: ;break;  //Wetterdaten
135
    case 4: ;break;  //Wetterdaten
136
    case 5: ;break;  //Wetterdaten
137
    case 6: ;break;  //Wetterdaten
138
    case 7: ;break;  //Wetterdaten
139
    case 8: ;break;  //Wetterdaten
140
    case 9: ;break;  //Wetterdaten
141
    case 10: ;break;  //Wetterdaten
142
    case 11: ;break;  //Wetterdaten
143
    case 12: ;break;  //Wetterdaten
144
    case 13: ;break;  //Wetterdaten
145
    case 14: ;break;  //Wetterdaten
146
    case 15: ;break;  //Rufbit für PTB
147
    case 16: ;break; //Keine Änderung der Zeitzone
148
    case 17: ;break;  //Zeitzone: dcf_timezone=dcf_timezone
149
    case 18: dcf_timezone+=1;break;  //Zeitzone: 
150
    case 19: ;break;  //keine Schaltsekunde
151
    case 20: dcf_sync();break;  //Beginn der Zeitinformation (immer 1)
152
    case 21: ;break;
153
    case 22: ;break;
154
    case 23: ;break;
155
    case 24: ;break;
156
    case 25: ;break;
157
    case 26: ;break;
158
    case 27: ;break;
159
    case 28: ;break;  //Parität: Minute
160
    case 29: ;break;
161
    case 30: ;break;
162
    case 31: ;break;
163
    case 32: ;break;
164
    case 33: ;break;
165
    case 34: ;break;
166
    case 35: ;break;  //Parität: Stunde
167
    case 36: ;break;
168
    case 37: ;break;
169
    case 38: ;break;
170
    case 39: ;break;
171
    case 40: ;break;
172
    case 41: ;break;
173
    case 42: ;break;
174
    case 43: ;break;
175
    case 44: ;break;
176
    case 45: ;break;
177
    case 46: ;break;
178
    case 47: ;break;
179
    case 48: ;break;
180
    case 49: ;break;
181
    case 50: ;break;
182
    case 51: ;break;
183
    case 52: ;break;
184
    case 53: ;break;
185
    case 54: ;break;
186
    case 55: ;break;
187
    case 56: ;break;
188
    case 57: ;break;
189
    case 58: ;break;  //Parität: Datum
190
    case 59: dcf_sync();break;  //keine Absenkung --> neue Minute
191
    default: dcf_sync();break;
192
  }
193
}
194
195
void dcf_1(void)
196
{
197
  switch(bit_number)
198
  {
199
    case 0: dcf_sync();break;  //Start einer neuen Minute, muß immer 0 sein
200
    case 1: ;break;  //Wetterdaten
201
    case 2: ;break;  //Wetterdaten
202
    case 3: ;break;  //Wetterdaten
203
    case 4: ;break;  //Wetterdaten
204
    case 5: ;break;  //Wetterdaten
205
    case 6: ;break;  //Wetterdaten
206
    case 7: ;break;  //Wetterdaten
207
    case 8: ;break;  //Wetterdaten
208
    case 9: ;break;  //Wetterdaten
209
    case 10: ;break;  //Wetterdaten
210
    case 11: ;break;  //Wetterdaten
211
    case 12: ;break;  //Wetterdaten
212
    case 13: ;break;  //Wetterdaten
213
    case 14: ;break;  //Wetterdaten
214
    case 15: ;break;  //Rufbit für PTB
215
    case 16: ;break; //Am Ende dieser Stunde wird auf MEZ/MESZ umgestellt
216
    case 17: dcf_timezone+=1;break;  //Zeitzone: 
217
    case 18: ;break;  //Zeitzone: dcf_timezone=dcf_timezone
218
    case 19: ;break;  //Am Ende diese Stunde wird eine Schaltsekunde eingefügt.
219
    case 20: ;break;  //Beginn der Zeitinformation (immer 1)
220
    case 21: dcf_minute+=1;dcf_minute_parity+=1;break;
221
    case 22: dcf_minute+=2;dcf_minute_parity+=1;break;
222
    case 23: dcf_minute+=4;dcf_minute_parity+=1;break;
223
    case 24: dcf_minute+=8;dcf_minute_parity+=1;break;
224
    case 25: dcf_minute+=10;dcf_minute_parity+=1;break;
225
    case 26: dcf_minute+=20;dcf_minute_parity+=1;break;
226
    case 27: dcf_minute+=40;dcf_minute_parity+=1;break;
227
    case 28: dcf_minute_parity+=1;break;  //Parität: Minute
228
    case 29: dcf_hour+=1;dcf_hour_parity+=1;break;
229
    case 30: dcf_hour+=2;dcf_hour_parity+=1;break;
230
    case 31: dcf_hour+=4;dcf_hour_parity+=1;break;
231
    case 32: dcf_hour+=8;dcf_hour_parity+=1;break;
232
    case 33: dcf_hour+=10;dcf_hour_parity+=1;break;
233
    case 34: dcf_hour+=20;dcf_hour_parity+=1;break;
234
    case 35: dcf_hour_parity+=1;break;  //Parität: Stunde
235
    case 36: dcf_day+=1;dcf_date_parity+=1;break;
236
    case 37: dcf_day+=2;dcf_date_parity+=1;break;
237
    case 38: dcf_day+=4;dcf_date_parity+=1;break;
238
    case 39: dcf_day+=8;dcf_date_parity+=1;break;
239
    case 40: dcf_day+=10;dcf_date_parity+=1;break;
240
    case 41: dcf_day+=20;dcf_date_parity+=1;break;
241
    case 42: dcf_week_day+=1;dcf_date_parity+=1;break;
242
    case 43: dcf_week_day+=2;dcf_date_parity+=1;break;
243
    case 44: dcf_week_day+=4;dcf_date_parity+=1;break;
244
    case 45: dcf_month+=1;dcf_date_parity+=1;break;
245
    case 46: dcf_month+=2;dcf_date_parity+=1;break;
246
    case 47: dcf_month+=4;dcf_date_parity+=1;break;
247
    case 48: dcf_month+=8;dcf_date_parity+=1;break;
248
    case 49: dcf_month+=10;dcf_date_parity+=1;break;
249
    case 50: dcf_year+=1;dcf_date_parity+=1;break;
250
    case 51: dcf_year+=2;dcf_date_parity+=1;break;
251
    case 52: dcf_year+=4;dcf_date_parity+=1;break;
252
    case 53: dcf_year+=8;dcf_date_parity+=1;break;
253
    case 54: dcf_year+=10;dcf_date_parity+=1;break;
254
    case 55: dcf_year+=20;dcf_date_parity+=1;break;
255
    case 56: dcf_year+=40;dcf_date_parity+=1;break;
256
    case 57: dcf_year+=80;dcf_date_parity+=1;break;
257
    case 58: dcf_date_parity+=1;break;  //Parität: Datum
258
    case 59: dcf_sync();break;  //keine Absenkung --> neue Minute
259
    default: dcf_sync();break;
260
  }
261
}
262
/////////////////////////
263
//Berechnung Schaltjahr//
264
/////////////////////////
265
void leap_year(void)
266
{
267
  if(year%4==0 && year%100!=0)
268
  {
269
    leapyear=1;  //Schaltjahr, da durch 4 teilbar aber nicht durch 100
270
  }
271
  else
272
  {
273
    if(year%4!=0)
274
    {
275
      leapyear=0;//Kein Schaltjahr, da nicht durch 4 teilbar
276
    }
277
    else
278
    {
279
      if(year%400==0)
280
      {
281
        leapyear=1;//Schaltjahre, da durch 400 teilbar
282
      }
283
      else
284
      {
285
        leapyear=0;//Kein Schaltjahr, da durch 100 teilbar aber nicht durch 400
286
      }
287
    }
288
  }
289
}
290
291
/////////////////////////////
292
//Interrupt Service Routine//
293
/////////////////////////////
294
//Der Compare Interrupt Handler wird aufgerufen, wenn TCNT0 = OCR0 = 250-1 ist (250 Schritte), d.h. genau alle 1 ms
295
ISR (TIMER1_COMPA_vect)
296
{
297
  millisecond++;  //Counter für die Millisekunden
298
  dataPC = PIND;  //Der aktuelle Pegel vom DCF-Modul wird eingelesen und in dataPC den anderen Funktionen zur Verfügung gestellt
299
  counter_high++;  //Counter für die Bit-Auswertung (Dauer des High-Pegels), Rücksetzen muß in den Funktionen geschehen
300
  counter_low++;  //Counter für die Bit-Auswertung (Dauer des Low-Pegels), Rücksetzen muß in den Funktionen geschehen
301
  if(millisecond==1000)  //"selbstlaufende" Uhr
302
  {
303
    second++;
304
    millisecond=0;
305
    if(second==60)
306
    {
307
      minute++;
308
      second=0;
309
    }
310
    if(minute==60)
311
    {
312
      hour++;
313
      minute=0;
314
    }
315
    if(hour==24)
316
    {
317
      day++;
318
      week_day++;
319
      hour=0;
320
    }
321
    if(week_day==8)
322
    {
323
      week_day=1;
324
    }
325
    switch(day)
326
    {
327
      case 29:  //Tag 28
328
      {
329
        leap_year();
330
        if(month==2 && leapyear==0)
331
        {
332
          month++;
333
          day=1;
334
        }
335
      }
336
      break;
337
338
      case 30:  //Tag 29
339
      {
340
        leap_year();
341
        if(month==2 && leapyear==1)
342
        {
343
          month++;
344
          day=1;
345
        }
346
      }
347
      break;
348
349
      case 31:  //Tag 30
350
      {
351
        if(month==4 || month==6 || month==9 || month==11)
352
        {
353
          month++;
354
          day=1;
355
        }
356
      }
357
      break;
358
359
      case 32:  //Tag 31
360
      {
361
        if(month==1 || month==3 || month==5 || month==7|| month==8 || month==10 || month==12)
362
        {
363
          month++;
364
          day=1;
365
        }
366
      }
367
      break;
368
369
      default: ;break;
370
    }
371
    if(month==13)
372
    {
373
      year++;
374
      month=1;
375
    }
376
  }
377
}
378
379
////////////////////////////////////////////////////////
380
//Zusammenführung der internen Daten und der DCF-Daten//
381
////////////////////////////////////////////////////////
382
void match_date(void)
383
{
384
  week_day=dcf_week_day;
385
  day=dcf_day;
386
  month=dcf_month;
387
  year=2000+dcf_year;
388
}
389
390
void match_time(void)
391
{
392
  millisecond=0;
393
  second=0;
394
  minute=dcf_minute;
395
  hour=dcf_hour;
396
  timezone=dcf_timezone;
397
}
398
399
///////////////////////
400
//DCF-Pegelauswertung//
401
///////////////////////
402
void level_analysis(void)
403
{
404
  if(dataPC & (1<<PIND2))
405
  {
406
407
    if(counter_low>=60 && counter_low<=140)  //logisch 0
408
    {
409
//      minute_frame[bit_number]=0;      
410
411
      dcf_0();
412
  
413
      bit_number++;
414
      dcf_second++;
415
416
      counter_high=0;
417
      counter_low=0;
418
    }
419
    else
420
    {
421
      if(counter_low>=160 && counter_low<=240)  //logisch 1
422
      {
423
//        minute_frame[bit_number]=1;      
424
        
425
        dcf_1();
426
427
        bit_number++;
428
429
        counter_high=0;
430
        counter_low=0;
431
      }
432
      else
433
      {
434
        counter_low=0;
435
      }
436
    }
437
  }
438
  else
439
  {
440
    if(counter_high>=1750 && counter_high<=1950)
441
    {
442
      if(bit_number==59 && dcf_minute_parity%2==0 && dcf_hour_parity%2==0 && dcf_date_parity%2==0)
443
      {
444
        bit_number=0;
445
446
        match_date();
447
        match_time();
448
      }
449
      else
450
      {
451
        dcf_date_reset();
452
        dcf_time_reset();
453
454
        counter_high=0;
455
456
        dcf_sync();
457
      }
458
459
      counter_high=0;
460
461
      dcf_date_reset();
462
      dcf_time_reset();
463
    }
464
  }
465
}
Gruß Jonas

von Karl H. (kbuchegg)


Lesenswert?

Wenn ein LCD flackert, dann liegt das praktisch immer an exzessiven 
Aufrufen der LCD-Lösch Funktion.
Ich kann leider deine Ausgabefunktion nicht sehen, bzw. wie und wo sie 
eingesetzt wird. D.h. man kann auch nicht verfolgen, wie oft während des 
Empfangs eines Telegrams ein Display-Update angestossen wird.

von holger (Gast)


Lesenswert?

void dcf_sync(void)
{
 ...
     dcf_sync();
...
    dcf_sync();
...
 }

Rekursiver Selbstaufruf. Naja.

von Karl H. (kbuchegg)


Lesenswert?

holger schrieb:

> Rekursiver Selbstaufruf. Naja.

Autsch: Wer macht denn aber auch sowas.
Ich hab nur nach Schleifen abgesucht.

von holger (Gast)


Lesenswert?

>> Rekursiver Selbstaufruf. Naja.
>
>Autsch: Wer macht denn aber auch sowas.
>Ich hab nur nach Schleifen abgesucht.

Die ist doch da;)

Rekursiver Selbstmord-> Reset -> Rekursiver Selbstmord-> Reset.
Display flackert weil es ständig neu initialisiert wird;)

von Jonas E. (jonas_e43)


Lesenswert?

Ich hatte die Quelldatei von einer DCF Uhr benutzt. (Siehe Anhang und 
sie etwas abgeändert. Aber dieser Aufruf soll ausgeführt werden...
siehe (Beitrag "DCF-Uhr mit LCD in C").
Habe den rekursiven Aufruf jetzt rausgenommen.
Aber leider wird immer noch nicht die korrekte Zeit empfangen

von R. F. (rfr)


Lesenswert?

Was ist mit assert?
was ist mit fprintf?
Warum programmierst du nicht so, dass og.  dir erklären, was dein 
Programm macht und du erkennen kannst, wann das davon abweicht, was es 
machen soll?`

Und poste den Quelltext doch bitte als Anhang.

Grüsse

Robert

von Karl H. (kbuchegg)


Lesenswert?

holger schrieb:

>>Autsch: Wer macht denn aber auch sowas.
>>Ich hab nur nach Schleifen abgesucht.
>
> Die ist doch da;)
>
> Rekursiver Selbstmord-> Reset -> Rekursiver Selbstmord-> Reset.

Das ist schon klar.
Ich habs nur nicht gesehen, weil ich gar nicht auf die Idee gekommen 
bin, da nach Rekursionen Ausschau zu halten.

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:

> Aber leider wird immer noch nicht die korrekte Zeit empfangen

Tja. Dann musst du eben Debuggen.

Ich würde mal damit anfangen, die ermittelten Zeiten mir wo ausgeben zu 
lassen und das dann mal studieren. Und zwar unabhängig von irgendeiner 
bereits implementierten Uhren-Software.

von Jonas E. (jonas_e43)


Angehängte Dateien:

Lesenswert?

Hier einmal der Programm Code, in welchem das DCF-Modul verwendet wird.
Vielleicht hilft das ein bisschen mehr.
Was meinst du mit assert und fprintf?
Ich bin noch ein Neuling in C und hoffe das ihr mir bei meine 
programmier Fautpas etwas helfen könnt.
Gruß Jonas

von Karl H. (kbuchegg)


Lesenswert?

Hmm. Der COde ist überhaupt etwas seltsam.
Such dir einen DCF-Code von Peter Danegger. Da gibts sicher was in der 
Codesammlung. Der funktioniert dann wenigstens auch.

von R. F. (rfr)


Lesenswert?

Jonas E. schrieb:
> Hier einmal der Programm Code, in welchem das DCF-Modul verwendet wird.
> Vielleicht hilft das ein bisschen mehr.

DU musst dir helfen. WIR geben Tips, aber eigentlich schreibt hier 
keiner Auftragssoftware.


> Was meinst du mit assert und fprintf?

Die Funktionen dieses Namens, nachzulesen in deriner Doku oder durch 
Googeln.

> Ich bin noch ein Neuling in C und hoffe das ihr mir bei meine
> programmier Fautpas etwas helfen könnt.

Das ist nicht vollkommen unbemerkt geblieben.
> Gruß Jonas


dto.
Robert

von Jonas E. (jonas_e43)


Lesenswert?

Natürlich versuche ich mir selbst zu helfen und ich würde auch nicht 
nachfragen, wenn ich selbst darauf gekommen wäre. Dies ist leider ja 
nicht der Fall.

von Jonas E. (jonas_e43)


Lesenswert?

Auf Karl Heinz Hinweis habe ich weiter nach einem möglichen DCF Code 
gesucht und auch einen gefunden. Dieser überprüft den INT0 Eingang und 
löst dann ein Interrupt aus. Nur leider empfängt der uC trotzdem nicht 
die Zeit...
Könnte das an den Interrupt Einstellungen liegen?

dcf_clock.c
1
/*#######################################################################################
2
AVR DCF77 Clock
3
4
Copyright (C) 2005 Ulrich Radig
5
6
#######################################################################################*/
7
8
#include "dcf_clock.h"
9
10
#include <avr/io.h>
11
#include <avr/interrupt.h>
12
13
14
//Die Uhrzeit seht in folgenden Variablen
15
volatile unsigned char ss   = 0;   //Globale Variable für die Sekunden
16
volatile unsigned char mm   = 0;   //Globale Variable für die Minuten
17
volatile unsigned char hh   = 0;   //Globale Variable für die Stunden
18
volatile unsigned char day   = 0;   //Globale Variable für den Tag
19
volatile unsigned char mon   = 0;   //Globale Variable für den Monat
20
volatile unsigned int year   = 0;   //Globale Variable für das Jahr
21
volatile bool shouldRender = false;
22
23
//Bitzähler für RX Bit
24
volatile unsigned char rx_bit_counter = 0;
25
26
//64 Bit für DCF77 benötigt werden 59 Bits
27
volatile unsigned long long dcf_rx_buffer = 0;
28
29
//Hilfs Sekunden Counter
30
volatile unsigned int h_ss = 0;
31
32
//Hilfs Variable für Stundenwechsel
33
volatile unsigned int h_hh = 0;
34
35
//############################################################################
36
//Overflow Interrupt wird ausgelöst bei 59Sekunde oder fehlenden DCF77 Signal
37
SIGNAL(TIMER1_OVF_vect)
38
//############################################################################
39
{
40
  struct  DCF77_Bits *rx_buffer;
41
  rx_buffer = (struct DCF77_Bits*)(char*)&dcf_rx_buffer;
42
  
43
  //Zurücksetzen des Timers
44
  TCNT1 = 65535 - (SYSCLK / 1024);
45
  //wurden alle 59 Bits empfangen und sind die Paritys richtig?
46
  if (rx_bit_counter == 59 &&
47
  flags.parity_P1 == rx_buffer->P1 &&
48
  flags.parity_P2 == rx_buffer->P2 &&
49
  flags.parity_P3 == rx_buffer->P3)
50
  //Alle 59Bits empfangen stellen der Uhr nach DCF77 Buffer
51
  {
52
    //Berechnung der Minuten BCD to HEX
53
    mm = rx_buffer->Min-((rx_buffer->Min/16)*6);
54
    
55
    if (mm != 0){mm--;}else{mm = 59; h_hh = 1;};
56
    
57
    //Berechnung der Stunden BCD to HEX
58
    hh = rx_buffer->Hour-((rx_buffer->Hour/16)*6);
59
60
    if (h_hh) {hh--;h_hh = 0;};
61
62
    //Berechnung des Tages BCD to HEX
63
    day= rx_buffer->Day-((rx_buffer->Day/16)*6);
64
    //Berechnung des Monats BCD to HEX
65
    mon= rx_buffer->Month-((rx_buffer->Month/16)*6);
66
    //Berechnung des Jahres BCD to HEX
67
    year= 2000 + rx_buffer->Year-((rx_buffer->Year/16)*6);
68
    //Sekunden werden auf 0 zurückgesetzt
69
    ss = 59;
70
    flags.dcf_sync = 1;
71
  }
72
  else
73
  //nicht alle 59Bits empfangen bzw kein DCF77 Signal Uhr läuft
74
  //manuell weiter
75
  {
76
    shouldRender = true;
77
    Add_one_Second();
78
    flags.dcf_sync = 0;
79
  }
80
  //zurücksetzen des RX Bit Counters
81
  rx_bit_counter = 0;
82
  //Löschen des Rx Buffers
83
  dcf_rx_buffer = 0;
84
};
85
86
//############################################################################
87
//DCF77 Modul empfängt Träger
88
SIGNAL (DCF77_INT)
89
//############################################################################
90
{
91
  //Auswertung der Pulseweite
92
  if (INT0_CONTROL == INT0_RISING_EDGE) //normal rising
93
  {
94
    flags.dcf_rx ^= 1;
95
    //Secunden Hilfs Counter berechnen // SYSCLK defined in USART.H
96
    h_ss = h_ss + TCNT1 - (65535 - (SYSCLK / 1024));
97
    //Zurücksetzen des Timers
98
    TCNT1 = 65535 - (SYSCLK / 1024);
99
    //ist eine Secunde verstrichen // SYSCLK defined in USART.H
100
    if (h_ss > (SYSCLK / 1024 / 100 * 90)) //90% von 1Sekunde
101
    {
102
      //Addiere +1 zu Sekunden
103
      Add_one_Second();
104
      //Zurücksetzen des Hilfs Counters
105
      h_ss = 0;
106
    };
107
    //Nächster Interrupt wird ausgelöst bei abfallender Flanke
108
    INT0_CONTROL = INT0_FALLING_EDGE;
109
  }
110
  else
111
  {
112
    //Auslesen der Pulsweite von ansteigender Flanke zu abfallender Flanke
113
    unsigned int pulse_wide = TCNT1;
114
    //Zurücksetzen des Timers
115
    TCNT1 = 65535 - (SYSCLK / 1024);
116
    //Secunden Hilfs Counter berechnen
117
    h_ss = h_ss + pulse_wide - (65535 - (SYSCLK / 1024));
118
    //Parity speichern
119
    //beginn von Bereich P1/P2/P3
120
    if (rx_bit_counter ==  21 || rx_bit_counter ==  29 || rx_bit_counter ==  36)
121
    {
122
      flags.parity_err = 0;
123
    };
124
    //Speichern von P1
125
    if (rx_bit_counter ==  28) {flags.parity_P1 = flags.parity_err;};
126
    //Speichern von P2
127
    if (rx_bit_counter ==  35) {flags.parity_P2 = flags.parity_err;};
128
    //Speichern von P3
129
    if (rx_bit_counter ==  58) {flags.parity_P3 = flags.parity_err;};
130
    //Überprüfen ob eine 0 oder eine 1 empfangen wurde
131
    //0 = 100ms
132
    //1 = 200ms
133
    //Abfrage größer als 150ms (15% von 1Sekund also 150ms)
134
    if (pulse_wide > (65535 - (SYSCLK / 1024)/100*85))
135
    {
136
      //Schreiben einer 1 im dcf_rx_buffer an der Bitstelle rx_bit_counter
137
      dcf_rx_buffer = dcf_rx_buffer | ((unsigned long long) 1 << rx_bit_counter);
138
      //Toggel Hilfs Parity
139
      flags.parity_err = flags.parity_err ^ 1;
140
    }
141
    //Nächster Interrupt wird ausgelöst bei ansteigender Flanke
142
    INT0_CONTROL = INT0_RISING_EDGE;
143
    //RX Bit Counter wird um 1 incrementiert
144
    rx_bit_counter++;
145
  }
146
};
147
148
//############################################################################
149
//Addiert 1 Sekunde
150
void Add_one_Second (void)
151
//############################################################################
152
{
153
  ss++;//Addiere +1 zu Sekunden
154
  if (ss == 60)
155
  {
156
    ss = 0;
157
    mm++;//Addiere +1 zu Minuten
158
    if (mm == 60)
159
    {
160
      mm = 0;
161
      hh++;//Addiere +1 zu Stunden
162
      if (hh == 24)
163
      {
164
        hh = 0;
165
      }
166
    }
167
  }
168
};
169
170
//############################################################################
171
//Diese Routine startet und inizialisiert den Timer
172
void Start_Clock (void)
173
//############################################################################
174
{
175
  //Interrupt DCF77 einschalten auf ansteigende Flanke
176
  DCF77_INT_ENABLE();
177
  INT0_CONTROL = INT0_RISING_EDGE; //Normal Rising Edge
178
  
179
  //Interrupt Overfolw enable
180
  TIMSK1 |= (1 << TOIE1);
181
  //Setzen des Prescaler auf 1024
182
  TCCR1B |= (1<<CS10 | 0<<CS11 | 1<<CS12);
183
  TCNT1 = 65535 - (SYSCLK / 1024);
184
  shouldRender = false;
185
  return;
186
};


dcf_clock.h
1
/*#######################################################################################
2
AVR DCF77 Clock
3
4
Copyright (C) 2005 Ulrich Radig
5
6
#######################################################################################*/
7
8
#ifndef _CLOCK_H
9
#define _CLOCK_H
10
11
#include <avr/io.h>
12
#include <avr/interrupt.h>
13
#include <stdbool.h>
14
15
/*typedef struct {
16
  
17
} time_t;*/
18
volatile unsigned char ss;  //Globale Variable für Sekunden
19
volatile unsigned char mm;  //Globale Variable für Minuten
20
volatile unsigned char hh;  //Globale Variable für Stunden
21
volatile unsigned char day;  //Globale Variable für den Tag
22
volatile unsigned char mon;  //Globale Variable für den Monat
23
volatile unsigned int year;  //Globale Variable für den Jahr
24
volatile bool shouldRender;
25
extern void Start_Clock (void); //Startet die DCF77 Uhr
26
extern void Add_one_Second (void);
27
28
#ifndef SYSCLK
29
    #define SYSCLK 14745600UL
30
#endif //SYSCLK  
31
32
//64 Bit für DCF77 benötigt werden 59 Bits
33
volatile unsigned long long dcf_rx_buffer;
34
//RX Pointer (Counter)
35
volatile extern unsigned char rx_bit_counter;
36
//Hilfs Sekunden Counter
37
volatile unsigned int h_ss;
38
39
#if defined (__AVR_ATmega32__)
40
//Interrupt an dem das DCF77 Modul hängt hier INT0
41
#define DCF77_INT_ENABLE()  GICR |= (1<<INT0);
42
#define DCF77_INT      INT0_vect
43
#define INT0_CONTROL    MCUCR
44
#define INT0_FALLING_EDGE  0x02
45
#define INT0_RISING_EDGE  0x03
46
#define TIMSK1         TIMSK
47
#endif
48
//Structur des dcf_rx_buffer
49
struct  DCF77_Bits {
50
  unsigned char M          :1  ;
51
  unsigned char O1      :1  ;
52
  unsigned char O2      :1  ;
53
  unsigned char O3      :1  ;
54
  unsigned char O4      :1  ;
55
  unsigned char O5      :1  ;
56
  unsigned char O6      :1  ;
57
  unsigned char O7      :1  ;
58
  unsigned char O8      :1  ;
59
  unsigned char O9      :1  ;
60
  unsigned char O10      :1  ;
61
  unsigned char O11      :1  ;
62
  unsigned char O12      :1  ;
63
  unsigned char O13      :1  ;
64
  unsigned char O14      :1  ;
65
  unsigned char R          :1  ;
66
  unsigned char A1      :1  ;
67
  unsigned char Z1      :1  ;
68
  unsigned char Z2      :1  ;
69
  unsigned char A2      :1  ;
70
  unsigned char S          :1  ;
71
  unsigned char Min      :7  ;//7 Bits für die Minuten
72
  unsigned char P1      :1  ;//Parity Minuten
73
  unsigned char Hour      :6  ;//6 Bits für die Stunden
74
  unsigned char P2      :1  ;//Parity Stunden
75
  unsigned char Day      :6  ;//6 Bits für den Tag
76
  unsigned char Weekday    :3  ;//3 Bits für den Wochentag
77
  unsigned char Month        :5  ;//3 Bits für den Monat
78
  unsigned char Year        :8  ;//8 Bits für das Jahr **eine 5 für das Jahr 2005**
79
  unsigned char P3      :1  ;//Parity von P2
80
};
81
82
struct
83
{
84
  volatile char parity_err          :1  ;//Hilfs Parity
85
  volatile char parity_P1          :1  ;//Berechnetes Parity P1
86
  volatile char parity_P2          :1  ;//Berechnetes Parity P2
87
  volatile char parity_P3          :1  ;//Berechnetes Parity P3
88
  volatile char dcf_rx          :1  ;//Es wurde ein Impuls empfangen
89
  volatile char dcf_sync          :1  ;//In der letzten Minuten wurde die Uhr syncronisiert
90
}flags;
91
92
#endif //_CLOCK_H

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:
> Auf Karl Heinz Hinweis habe ich weiter nach einem möglichen DCF Code
> gesucht und auch einen gefunden. Dieser überprüft den INT0 Eingang und
> löst dann ein Interrupt aus. Nur leider empfängt der uC trotzdem nicht
> die Zeit...
> Könnte das an den Interrupt Einstellungen liegen?

Probiers halt aus.
Schmeiss aus dem Programm alles ausser dem
1
//############################################################################
2
//DCF77 Modul empfängt Träger
3
SIGNAL (DCF77_INT)
4
//############################################################################
5
{
6
}

und den Interrupt Einstellungen raus, lass im Interrupt eine LED toggeln 
und dann siehst du nach ob die im richtigen Takt blinkt.

Die Technik, ich such mir da einen Code und alles ist in Butter, 
funktioniert manchmal. Manchmal funktioniert sie aber NICHT. Und dann 
bist du mit deinen Debug-Fähigkeiten gefragt. Und die beginnen nun mal 
damit, dass man von vorne bis hinten alles überprüft. Der Code ist 
darauf angewiesen einen regelmässigen Aufruf der ISR, abgeleitet vom 
Signal des DCF Empfängers zu kriegen. Also wird das mal geprüft. Dazu 
brauch ich keine DCF Auswertung, dazu brauch ich keine Uhr.
Einfach den DCF-Empfänger an den Mega ankabeln und nachsehen ob die 
Interrupts kommen oder nicht. Kommen sie, dann ist der Teil mal abgehakt 
und ich nehm mir den nächsten Schritt vor. Kommen sie nicht, dann muss 
man dem nachgehen warum sie nicht kommen.

Und so geht das sukzessive voran.
So ist das nun mal. µC-Hardware sind unterschiedliche. DCF-Empfänger 
sind unterschiedlich. Das ist nicht so wie am PC, wo welteweit 847 
Millionen PC sich unter Windows mehr oder weniger gleich verhalten und 
man daher ein Programm von einem Japaner auf seinen PC laden kann und 
das läuft aus dem Stand heraus.

von Jonas E. (jonas_e43)


Lesenswert?

Okay.
Ich habe die ISR jetzt so angepasst.
1
//############################################################################
2
//DCF77 Modul empfängt Träger
3
SIGNAL (DCF77_INT)
4
//############################################################################
5
{
6
  if (PIND & (1<<PD6))
7
  PORTD &= ~(1<<PD6);
8
  else
9
  PORTD |= ( 1 << PD6 );
10
};

Die LED geht leider nur am Anfang an und nicht wieder aus.
Ich benutze diese Interrupt Einstellungen:
1
#define DCF77_INT_ENABLE()  GICR |= (1<<INT0);
2
#define DCF77_INT      INT0_vect
3
#define INT0_CONTROL    MCUCR
4
#define INT0_FALLING_EDGE  0x02
5
#define INT0_RISING_EDGE  0x03
6
#define TIMSK1         TIMSK

1
DCF77_INT_ENABLE();
2
INT0_CONTROL = INT0_RISING_EDGE; //Normal Rising Edge

Woher könnte das wohl kommen?

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:

> Woher könnte das wohl kommen?

Das könnte zb davon kommen, dass dein DCF Modul zu schwach auf der Brust 
ist, um den Pin auf High oder Low zu ziehen. Einigen Pollin Modulen sagt 
man zb nach, dass sie ohne Signalaufbereitung da probleme haben.


Es könnte aber auch sein, dass dein DCF Modul einen Open-Collector 
Ausgang hat und daher ein Pullup-Widerstand an die Signalleitung muss.

von Jonas E. (jonas_e43)


Lesenswert?

Ich benutze das DCF Modul von ELV 
(http://www.elv.de/dcf-empfangsmodul-dcf-2.html). Habe schon zwischen 
Data und VCC einen 10k Pull Up Widerstand geschaltet.

von Karl H. (kbuchegg)


Lesenswert?

Dann eben noch einen Schritt einfacher:

Programm welches den Pegel des Input Pins, an dem das Modul hängt auf 
eine LED ausgibt. Blinkt die LED - ja oder nein?

Alternativ könnte man da auch eine Transistorstufe direkt an den Ausgang 
hängen und damit mal nachsehen, ob da aus dem Modul überhaupt was 
rauskommt. Aber wenn ich einen µC habe, der mit dem richtigen Programm 
mir dieselbe Information liefern kann, dann ziehe ich das normalerweise 
vor.

von Mr. Tom (Gast)


Lesenswert?

Jonas E. schrieb:
> Könnte das an den Interrupt Einstellungen liegen?

Könntest du deine seitenlangen Quelltext vielleich mal als Anhang 
anfügen? So ist es arg schwierig, die Beiträge dazwischen rauszufiltern.

von Jonas E. (jonas_e43)


Lesenswert?

Muss ich den Pin PD2 auf Input schalten, damit ein Interrupt ausgelöst 
werden kann?

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:
> Muss ich den Pin PD2 auf Input schalten, damit ein Interrupt ausgelöst
> werden kann?

Das wäre der Situation ... sagen wir mal ... zuträglich.

von Jonas E. (jonas_e43)


Lesenswert?

So ich bin jetzt mal ganz vom Anfang gestartet.
Ich hab eine LED zwischen dem Daten Pin des DCF Moduls und dem GND PIN 
des Moduls gehalten. Die Led blinkt jede Sekunde. Das müsste doch 
bedeuten, dass das Modul noch funktioniert oder?

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:
> So ich bin jetzt mal ganz vom Anfang gestartet.
> Ich hab eine LED zwischen dem Daten Pin des DCF Moduls und dem GND PIN
> des Moduls gehalten. Die Led blinkt jede Sekunde. Das müsste doch
> bedeuten, dass das Modul noch funktioniert oder?

So kann man das interpretieren.

Ergo - nächster Schritt:
Daten-Leitung an den µC Pin und einfach nur mal einlesen und eine LED 
entsprechend schalten.

Danach dann dasselbe mit einem externen Interrupt.

von Jonas E. (jonas_e43)


Lesenswert?

Funktioniert auch.
Die Led am Atmega32 blikt in der ISR Routine in einem bestimmten 
Rhythmus.

von Karl H. (kbuchegg)


Lesenswert?

Jonas E. schrieb:
> Funktioniert auch.
> Die Led am Atmega32 blikt in der ISR Routine in einem bestimmten
> Rhythmus.

Schön.
Dann füll die ISR mit Leben - sprich mit Code, den du dir bei deinen 
"Vorlagen" ausleihst.

von Jonas E. (jonas_e43)


Lesenswert?

Hab ich gemacht,
nur leider wird die Uhrzeit nicht auf die aktuellen Daten geändert...
Könnte das am invertieren Signal liegen?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.