Forum: Mikrocontroller und Digitale Elektronik DCF77-Programm-Multitaskingproblem


von Oliver G. (suchoi31)


Lesenswert?

Guten Tag,

Vorab:
Microcontroller:Atmega32
Frequenz:16MHz
DCF-Modul:Conrad
Entwicklungsumgebung:AVR-Studio 4.18 Build 684
WinAVR_20100110
STK 500



ich habe das Dekodierprogramm von Johannes M. etwas modifiziert und habe 
mich gewundert, warum ich nicht parallel mehere Operationen gleichzeitig 
ausführen kann, ohne das der DCF-Empfang beeinflusst wird.

Wenn ich nun etwas in die while-Schleife der main Funktion 
hineinschreibe, beispielsweise ein Temperaturauswertprogramm oder ein 
Programm das einen weckt, kommt der Dekodiervorgang des DCF-Signals 
sofort durcheinander und er findet nicht mehr den Beginn einer neuen 
Minute. Auch wenn komplett ohne Delays gearbeitet wird.

Kann mir Jemand sagen woran das liegen könnte?

Hier der Programmcode zur Überprüfung.
1
//DCF-Uhr mit LCD20x4
2
//ATmega16 @ 16 MHz
3
//Autor: Johannes Maslowski
4
//Version 2010-02-28-00-11
5
//AVR-Studio 4.18 Build 692, WinAVR 20100110
6
7
//Header Dateien
8
#include <avr/io.h>
9
#include <avr/interrupt.h>
10
#include <stdlib.h>
11
#include "lcd-routines.h"
12
13
/////////////
14
//Variablen//
15
/////////////
16
//date
17
unsigned char week_day;
18
unsigned char day;
19
unsigned char month;
20
unsigned int  year;
21
22
//time
23
unsigned int  hundertstelsecond;
24
unsigned char second;
25
unsigned char minute;
26
unsigned char hour;
27
unsigned char timezone;
28
29
//Weckzeit
30
unsigned char alarm_stunde=17;
31
unsigned char alarm_minute=20;
32
33
//Temperatur
34
int temperatur;
35
36
//Speicherbereich für DCF-Pegel
37
unsigned char dataPC;
38
39
//Pegel-Auswertung
40
unsigned int counter_high;
41
unsigned int counter_low;
42
unsigned char bit_number;
43
44
//dcf_date
45
unsigned char dcf_week_day;
46
unsigned char dcf_day;
47
unsigned char dcf_month;
48
unsigned char dcf_year;
49
unsigned char dcf_date_parity;
50
51
//dcf_time
52
unsigned char dcf_second;
53
unsigned char dcf_minute;
54
unsigned char dcf_minute_parity;
55
unsigned char dcf_hour;
56
unsigned char dcf_hour_parity;
57
unsigned char dcf_timezone;
58
59
//Puffer für die int --> char Umwandlung
60
char itoa_buffer[8];
61
62
//Array für die DCF-Datenbits
63
//uint8_t minute_frame[60];  //wird noch nicht genutzt
64
65
//Schaltjahr
66
unsigned char leapyear;
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
//Sonstiges//
98
/////////////
99
//Eine führende 0 ergänzen bei Zahlen kleiner/gleich 9
100
void leading_0(unsigned char digit)
101
{
102
  if(digit<=9)
103
  {
104
    lcd_data('0');
105
  }
106
}
107
108
/////////////////
109
//LCD-Ausgaben///
110
/////////////////
111
112
//Intelligy Schriftzug
113
void show_intelligy_string(unsigned char column,unsigned char row) //Übergabe der Cursorposition (Spalte,Zeile)
114
{
115
    set_cursor(column,row);
116
117
  lcd_string("Intelligy Clock");
118
}
119
120
//Zusammengeführte Zeit
121
void show_matched_time(unsigned char column,unsigned char row)  //Übergabe der Cursorposition (Spalte,Zeile)
122
{
123
  set_cursor(column,row);
124
125
  //LCD-Ausgabe: Stunde
126
  leading_0(hour);
127
  itoa(hour,itoa_buffer,10);
128
  lcd_string(itoa_buffer);
129
  lcd_data(':');
130
131
  //LCD-Ausgabe: Minute
132
  leading_0(minute);
133
   itoa(minute,itoa_buffer,10);
134
  lcd_string(itoa_buffer);
135
  lcd_data(':');
136
137
  //LCD-Ausgabe: Sekunde
138
  leading_0(second);
139
   itoa(second,itoa_buffer,10);
140
  lcd_string(itoa_buffer);
141
//  lcd_data(' ');
142
143
}
144
145
//Zusammengeführtes Datum
146
void show_matched_date(unsigned char column,unsigned char row)  //Übergabe der Cursorposition (Spalte,Zeile)
147
{
148
  set_cursor(column,row);
149
150
  //LCD-Ausgabe: Wochentag
151
  switch(week_day)
152
  {
153
    case 1: lcd_string("Mo,  ");break;  //LCD-Ausgabe: Montag
154
    case 2: lcd_string("Di,  ");break;  //LCD-Ausgabe: Dienstag
155
    case 3: lcd_string("Mi,  ");break;  //LCD-Ausgabe: Mittwoch
156
    case 4: lcd_string("Do,  ");break;  //LCD-Ausgabe: Donnerstag
157
    case 5: lcd_string("Fr,  ");break;  //LCD-Ausgabe: Freitag
158
    case 6: lcd_string("Sa,  ");break;  //LCD-Ausgabe: Samstag
159
    case 7: lcd_string("So,  ");break;  //LCD-Ausgabe: Sonntag
160
    default:lcd_string("     ");break;
161
  }
162
  
163
  //LCD-Ausgabe: Tag
164
  leading_0(day);
165
  itoa(day,itoa_buffer,10);
166
  lcd_string(itoa_buffer);
167
  lcd_data('.');
168
169
  //LCD-Ausgabe: Monat
170
  leading_0(month);
171
   itoa(month,itoa_buffer,10);
172
  lcd_string(itoa_buffer);
173
  lcd_string(".");
174
175
  //LCD-Ausgabe: Jahreszahl
176
  leading_0(year);
177
   itoa(year,itoa_buffer,10);
178
  lcd_string(itoa_buffer);
179
}
180
181
//Weckzeit
182
void show_weckzeit(unsigned char column,unsigned char row)//Übergabe der Cursorposition (Spalte,Zeile)
183
{
184
185
set_cursor(column,row);
186
187
 
188
 lcd_string("Weckzeit: ");
189
 
190
 //LCD Ausgabe Weckstunde
191
192
 leading_0(alarm_stunde);
193
 itoa(alarm_stunde,itoa_buffer,10);
194
 lcd_string(itoa_buffer);
195
 lcd_string(":");
196
197
 //LCD Ausgabe Weckminute
198
199
 leading_0(alarm_minute);
200
 itoa(alarm_minute,itoa_buffer,10);
201
 lcd_string(itoa_buffer);
202
203
204
205
}
206
207
208
//Temperatur
209
void show_temperatur(unsigned char column,unsigned char row)//Übergabe der Cursorposition (Spalte,Zeile)
210
{
211
212
set_cursor(column,row);
213
214
 //LCD Ausgabe Temperatur
215
216
 itoa(temperatur,itoa_buffer,10);
217
 lcd_string(itoa_buffer);
218
 
219
 lcd_string("°C");
220
}
221
222
///////////////////////////
223
//DCF-Synchronisation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
224
//High-Pegel muß für 1700-1900ms anliegen
225
//Danach muß ein Low-Pegel folgen
226
void dcf_sync(void)
227
{
228
  show_matched_date(0,3);
229
  show_matched_time(6,2);
230
  show_weckzeit(0,4);
231
  show_temperatur(17,4);
232
233
  //LCD-Ausgabe: Synchronisation läuft gerade
234
  set_cursor(19,1);
235
  lcd_data('?');
236
237
  if(!(dataPC & (1<<PINC1)))
238
  {
239
    if(counter_high>=175 && counter_high<=195)
240
    {
241
      //LCD-Ausgabe: Synchronisation erfolgreich
242
      set_cursor(19,1);
243
      lcd_data('!');
244
245
      counter_reset();
246
      dcf_date_reset();
247
      dcf_time_reset();
248
    }
249
    else
250
    {
251
      counter_high=0;
252
      dcf_sync();
253
    }
254
  }
255
  else
256
  {
257
    dcf_sync();
258
  }
259
}
260
261
//////////////////
262
//DCF-Auswertung//
263
//////////////////
264
void dcf_0(void)
265
{
266
  switch(bit_number)
267
  {
268
    case 0: ;break;  //Start einer neuen Minuten, muß immer 0 sein
269
    case 1: ;break;  //Wetterdaten
270
    case 2: ;break;  //Wetterdaten
271
    case 3: ;break;  //Wetterdaten
272
    case 4: ;break;  //Wetterdaten
273
    case 5: ;break;  //Wetterdaten
274
    case 6: ;break;  //Wetterdaten
275
    case 7: ;break;  //Wetterdaten
276
    case 8: ;break;  //Wetterdaten
277
    case 9: ;break;  //Wetterdaten
278
    case 10: ;break;  //Wetterdaten
279
    case 11: ;break;  //Wetterdaten
280
    case 12: ;break;  //Wetterdaten
281
    case 13: ;break;  //Wetterdaten
282
    case 14: ;break;  //Wetterdaten
283
    case 15: ;break;  //Rufbit für PTB
284
    case 16: ;break; //Keine Änderung der Zeitzone
285
    case 17: ;break;  //Zeitzone: dcf_timezone=dcf_timezone
286
    case 18: dcf_timezone+=1;break;  //Zeitzone: 
287
    case 19: ;break;  //keine Schaltsekunde
288
    case 20: dcf_sync();break;  //Beginn der Zeitinformation (immer 1)
289
    case 21: ;break;
290
    case 22: ;break;
291
    case 23: ;break;
292
    case 24: ;break;
293
    case 25: ;break;
294
    case 26: ;break;
295
    case 27: ;break;
296
    case 28: ;break;  //Parität: Minute
297
    case 29: ;break;
298
    case 30: ;break;
299
    case 31: ;break;
300
    case 32: ;break;
301
    case 33: ;break;
302
    case 34: ;break;
303
    case 35: ;break;  //Parität: Stunde
304
    case 36: ;break;
305
    case 37: ;break;
306
    case 38: ;break;
307
    case 39: ;break;
308
    case 40: ;break;
309
    case 41: ;break;
310
    case 42: ;break;
311
    case 43: ;break;
312
    case 44: ;break;
313
    case 45: ;break;
314
    case 46: ;break;
315
    case 47: ;break;
316
    case 48: ;break;
317
    case 49: ;break;
318
    case 50: ;break;
319
    case 51: ;break;
320
    case 52: ;break;
321
    case 53: ;break;
322
    case 54: ;break;
323
    case 55: ;break;
324
    case 56: ;break;
325
    case 57: ;break;
326
    case 58: ;break;  //Parität: Datum
327
    case 59: dcf_sync();break;  //keine Absenkung --> neue Minute
328
    default: dcf_sync();break;
329
  }
330
}
331
332
void dcf_1(void)
333
{
334
  switch(bit_number)
335
  {
336
    case 0: dcf_sync();break;  //Start einer neuen Minute, muß immer 0 sein
337
    case 1: ;break;  //Wetterdaten
338
    case 2: ;break;  //Wetterdaten
339
    case 3: ;break;  //Wetterdaten
340
    case 4: ;break;  //Wetterdaten
341
    case 5: ;break;  //Wetterdaten
342
    case 6: ;break;  //Wetterdaten
343
    case 7: ;break;  //Wetterdaten
344
    case 8: ;break;  //Wetterdaten
345
    case 9: ;break;  //Wetterdaten
346
    case 10: ;break;  //Wetterdaten
347
    case 11: ;break;  //Wetterdaten
348
    case 12: ;break;  //Wetterdaten
349
    case 13: ;break;  //Wetterdaten
350
    case 14: ;break;  //Wetterdaten
351
    case 15: ;break;  //Rufbit für PTB
352
    case 16: ;break; //Am Ende dieser Stunde wird auf MEZ/MESZ umgestellt
353
    case 17: dcf_timezone+=1;break;  //Zeitzone: 
354
    case 18: ;break;  //Zeitzone: dcf_timezone=dcf_timezone
355
    case 19: ;break;  //Am Ende diese Stunde wird eine Schaltsekunde eingefügt.
356
    case 20: ;break;  //Beginn der Zeitinformation (immer 1)
357
    case 21: dcf_minute+=1;dcf_minute_parity+=1;break;
358
    case 22: dcf_minute+=2;dcf_minute_parity+=1;break;
359
    case 23: dcf_minute+=4;dcf_minute_parity+=1;break;
360
    case 24: dcf_minute+=8;dcf_minute_parity+=1;break;
361
    case 25: dcf_minute+=10;dcf_minute_parity+=1;break;
362
    case 26: dcf_minute+=20;dcf_minute_parity+=1;break;
363
    case 27: dcf_minute+=40;dcf_minute_parity+=1;break;
364
    case 28: dcf_minute_parity+=1;break;  //Parität: Minute
365
    case 29: dcf_hour+=1;dcf_hour_parity+=1;break;
366
    case 30: dcf_hour+=2;dcf_hour_parity+=1;break;
367
    case 31: dcf_hour+=4;dcf_hour_parity+=1;break;
368
    case 32: dcf_hour+=8;dcf_hour_parity+=1;break;
369
    case 33: dcf_hour+=10;dcf_hour_parity+=1;break;
370
    case 34: dcf_hour+=20;dcf_hour_parity+=1;break;
371
    case 35: dcf_hour_parity+=1;break;  //Parität: Stunde
372
    case 36: dcf_day+=1;dcf_date_parity+=1;break;
373
    case 37: dcf_day+=2;dcf_date_parity+=1;break;
374
    case 38: dcf_day+=4;dcf_date_parity+=1;break;
375
    case 39: dcf_day+=8;dcf_date_parity+=1;break;
376
    case 40: dcf_day+=10;dcf_date_parity+=1;break;
377
    case 41: dcf_day+=20;dcf_date_parity+=1;break;
378
    case 42: dcf_week_day+=1;dcf_date_parity+=1;break;
379
    case 43: dcf_week_day+=2;dcf_date_parity+=1;break;
380
    case 44: dcf_week_day+=4;dcf_date_parity+=1;break;
381
    case 45: dcf_month+=1;dcf_date_parity+=1;break;
382
    case 46: dcf_month+=2;dcf_date_parity+=1;break;
383
    case 47: dcf_month+=4;dcf_date_parity+=1;break;
384
    case 48: dcf_month+=8;dcf_date_parity+=1;break;
385
    case 49: dcf_month+=10;dcf_date_parity+=1;break;
386
    case 50: dcf_year+=1;dcf_date_parity+=1;break;
387
    case 51: dcf_year+=2;dcf_date_parity+=1;break;
388
    case 52: dcf_year+=4;dcf_date_parity+=1;break;
389
    case 53: dcf_year+=8;dcf_date_parity+=1;break;
390
    case 54: dcf_year+=10;dcf_date_parity+=1;break;
391
    case 55: dcf_year+=20;dcf_date_parity+=1;break;
392
    case 56: dcf_year+=40;dcf_date_parity+=1;break;
393
    case 57: dcf_year+=80;dcf_date_parity+=1;break;
394
    case 58: dcf_date_parity+=1;break;  //Parität: Datum
395
    case 59: dcf_sync();break;  //keine Absenkung --> neue Minute
396
    default: dcf_sync();break;
397
  }
398
}
399
/////////////////////////
400
//Berechnung Schaltjahr//
401
/////////////////////////
402
void leap_year(void)
403
{
404
  if(year%4==0 && year%100!=0)
405
  {
406
    leapyear=1;  //Schaltjahr, da durch 4 teilbar aber nicht durch 100
407
  }
408
  else
409
  {
410
    if(year%4!=0)
411
    {
412
      leapyear=0;//Kein Schaltjahr, da nicht durch 4 teilbar
413
    }
414
    else
415
    {
416
      if(year%400==0)
417
      {
418
        leapyear=1;//Schaltjahre, da durch 400 teilbar
419
      }
420
      else
421
      {
422
        leapyear=0;//Kein Schaltjahr, da durch 100 teilbar aber nicht durch 400
423
      }
424
    }
425
  }
426
}
427
428
429
/////////////////////////////////
430
//Interrupt Service Routine/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
431
//Der Compare Interrupt Handler wird aufgerufen, wenn TCNT0 = OCR0 = 156-1 ist (250 Schritte), d.h. genau alle 10 ms
432
ISR (TIMER0_COMP_vect)
433
{
434
  hundertstelsecond++;  //Counter für die Millisekunden
435
  dataPC = PINC;  //Der aktuelle Pegel vom DCF-Modul wird eingelesen und in dataPC den anderen Funktionen zur Verfügung gestellt
436
  counter_high++;  //Counter für die Bit-Auswertung (Dauer des High-Pegels), Rücksetzen muß in den Funktionen geschehen
437
  counter_low++;  //Counter für die Bit-Auswertung (Dauer des Low-Pegels), Rücksetzen muß in den Funktionen geschehen
438
  if(hundertstelsecond==100)  //"selbstlaufende" Uhr
439
  {
440
    second++;
441
    hundertstelsecond=0;
442
    if(second==60)
443
    {
444
      minute++;
445
      second=0;
446
447
    }
448
    if(minute==60)
449
    {
450
      hour++;
451
      minute=0;
452
    }
453
    if(hour==24)
454
    {
455
      day++;
456
      week_day++;
457
      hour=0;
458
    }
459
    if(week_day==8)
460
    {
461
      week_day=1;
462
    }
463
    switch(day)
464
    {
465
      case 29:  //Tag 28
466
      {
467
        leap_year();
468
        if(month==2 && leapyear==0)
469
        {
470
          month++;
471
          day=1;
472
        }
473
      }
474
      break;
475
476
      case 30:  //Tag 29
477
      {
478
        leap_year();
479
        if(month==2 && leapyear==1)
480
        {
481
          month++;
482
          day=1;
483
        }
484
      }
485
      break;
486
487
      case 31:  //Tag 30
488
      {
489
        if(month==4 || month==6 || month==9 || month==11)
490
        {
491
          month++;
492
          day=1;
493
        }
494
      }
495
      break;
496
497
      case 32:  //Tag 31
498
      {
499
        if(month==1 || month==3 || month==5 || month==7|| month==8 || month==10 || month==12)
500
        {
501
          month++;
502
          day=1;
503
        }
504
      }
505
      break;
506
507
      default: ;break;
508
    }
509
    if(month==13)
510
    {
511
      year++;
512
      month=1;
513
    }
514
  }
515
}
516
517
////////////////////////////////////////////////////////
518
//Zusammenführung der internen Daten und der DCF-Daten//
519
////////////////////////////////////////////////////////
520
521
void match_date(void)
522
{
523
  week_day=dcf_week_day;
524
  day=dcf_day;
525
  month=dcf_month;
526
  year=2000+dcf_year;
527
}
528
529
void match_time(void)
530
{
531
  hundertstelsecond=0;
532
  second=0;
533
  minute=dcf_minute;
534
  hour=dcf_hour;
535
  timezone=dcf_timezone;
536
}
537
538
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
539
//////Weckzeit///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
540
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
541
542
void weckzeit(void)
543
{
544
  if(alarm_stunde==hour)
545
  {
546
    if(alarm_minute==minute)
547
  {   
548
    if(PORTB >= 0x80)  //wenn LED 8 ein dann
549
      PORTB = 0x01;  //setzte wieder LED 1
550
    else
551
      PORTB = PORTB << 1;  //ansonsten zähle hoch
552
553
//    zeit(500);     //0,5s warten    
554
    }
555
    else
556
    {
557
    PORTB=0x02;
558
    }
559
  }
560
  else
561
    {
562
    PORTB=0x02;
563
    } 
564
}
565
566
///////////////////////
567
//DCF-Pegelauswertung//
568
///////////////////////
569
void level_analysis(void)
570
{
571
  if(dataPC & (1<<PINC1))
572
  {
573
574
    if(counter_low>=3 && counter_low<=15)  //logisch 0
575
    {
576
//      minute_frame[bit_number]=0;      
577
578
      dcf_0();
579
  
580
      bit_number++;
581
      dcf_second++;
582
583
      counter_high=0;
584
      counter_low=0;
585
    }
586
    else
587
    {
588
      if(counter_low>=16 && counter_low<=30)  //logisch 1
589
      {
590
//        minute_frame[bit_number]=1;      
591
        
592
        dcf_1();
593
594
        bit_number++;
595
596
        counter_high=0;
597
        counter_low=0;
598
      }
599
      else
600
      {
601
        counter_low=0;
602
      }
603
    }
604
  }
605
  else
606
  {
607
    if(counter_high>=175 && counter_high<=195)
608
    {
609
      if(bit_number==59 && dcf_minute_parity%2==0 && dcf_hour_parity%2==0 && dcf_date_parity%2==0)
610
      {
611
        bit_number=0;
612
613
        match_date();
614
        match_time();
615
      }
616
      else
617
      {
618
        dcf_date_reset();
619
        dcf_time_reset();
620
621
        counter_high=0;
622
623
        if(year==0)
624
        {
625
        dcf_sync();
626
          }
627
      }
628
629
      counter_high=0;
630
631
      dcf_date_reset();
632
      dcf_time_reset();
633
    }
634
  }
635
}
636
637
638
639
////////
640
//Main//
641
////////
642
int main(void)
643
{
644
  //Setzen der Port-Richtungsregister
645
  DDRC &= ~(1<<PC1);  //PC1 Eingang (0)
646
  DDRB = 0xff;
647
  //Initialisieren der Ports
648
  PORTC |= (1<<PC1);  //PC1 Pull-Up gesetzt (1)
649
650
  lcd_init();  //Initialisierung des LCDs
651
652
  // Timer 0 konfigurieren
653
  TCCR0 = (1<<WGM01) | (1<<CS00) | (1<<CS02);  //CTC Modus (1), Prescaler 1024 (1) (1)
654
  OCR0 = 156-1; //((16000000/1024)/100) = 156,25
655
  TIMSK |= (1<<OCIE0);  //Compare Interrupt erlauben (1)
656
  sei();  //Global Interrupts aktivieren
657
658
  dcf_sync();  //Synchronisierung des DCF-Moduls
659
660
  while(1)
661
  {
662
  level_analysis();
663
  show_matched_date(0,3);
664
  show_matched_time(6,2);
665
//  show_weckzeit(0,4);
666
//  show_temperatur(17,4);
667
    weckzeit();
668
  
669
670
  
671
  }
672
}
Bin schon sehr gespannt auf eure Ratschläge.

Grüße Oli

: Bearbeitet durch User
von Lurchi (Gast)


Lesenswert?

Das Programm macht die Erkennung des Eingangssignal in der While() 
Schleife im Hauptprogramm. Wenn da zu große Verzögerungen eingebaut 
sind, gibt es halt Probleme.

Ich würde einen komplett anderen Programmaufbau wählen, so dass die DCF 
Decodierung komplett im Interrupt läuft: Etwa mit einem Interrupt zum 
Anfang jeder Sekunde und einem etwa 150 ms später. Das Signal vom 
Empfänger dann vorzugsweise auf den ICP Eingang.

von Karl H. (kbuchegg)


Lesenswert?

Oliver Go schrieb:

> ich habe das Dekodierprogramm von Johannes M. etwas modifiziert und habe
> mich gewundert, warum ich nicht parallel mehere Operationen gleichzeitig
> ausführen kann, ohne das der DCF-Empfang beeinflusst wird.

Das kommt daher, weil der ganze Programmaufbau mies ist.

von Karl H. (kbuchegg)


Lesenswert?

Abgesehen vom Einbau des DCF Teiles.
So was
1
void dcf_sync(void)
2
{
3
...
4
  if(!(dataPC & (1<<PINC1)))
5
  {
6
    if(counter_high>=175 && counter_high<=195)
7
...
8
    else
9
    {
10
      dcf_sync();
11
    }
12
  }
13
  else
14
  {
15
    dcf_sync();
16
  }
17
}

geht schon mal gar nicht.
So eine Rekursion kannst du am PC machen, auf dem du Megabyteweise 
Speicher hast. Aber auf einem kleinen µC mit seinem eher bescheidenem 
SRAM kannst du das nicht machen, ohne dass dir mehr oder weniger sofort 
der Speicher ausgeht.
Es ist auch nicht notwendig, dass du hier Rekursionen einsetzt. Die 
Funktionalität lässt sich mit while Schleifen wunderbar und viel simpler 
implementieren.

Edit:
Mal abgesehen davon, dass man das ganz sicher nicht so macht, dass der 
µC aktiv auf den Puls wartet. Hat dein DCF-Modul keinen (oder 
schlechten) Empfang (warum auch immer), dann steht die komplette Uhr.

Fazit: Ich hoffe Johannes hat in der Zwischenzeit gelernt. Muss er 
eigentlich, das Projekt ist ja dann doch schon recht alt). Aber so gehts 
nicht. Dieser Code ist ziemlich mies. und du solltest lernen, dass du 
dich nicht an Projekte halten sollst, in denen im Eröffnungsposting 
steht, dass der Autor selbst Anfänger ist. Das einzige was man im 
Normalfall von denen lernen kann, das ist wie man es nicht macht. Es 
gibt ein paar Leute, die in der Codesammlung wirklich guten Code 
veröffentlicht haben und an die du dich jederzeit halten kannst. Allen 
voran ist sicherlich Peter Danegger zu nennen. Von dem kannst du 
eigentlich ungeschaut so ziemlich jeden Code hernehmen und studieren und 
dabei eine Menge lernen.

: Bearbeitet durch User
von Cube_S (Gast)


Lesenswert?

Ich gebe mal meinen Code zum besten:
1
#define MIN_GAP 480
2
#define MAX_GAP 520
3
#define MIN_SEC 240
4
#define MAX_SEC 260
5
6
static bool dcf_state = false;
7
static bool dcf_parity = false;
8
static bool dcf_ok = false;
9
static uint16_t dcf_high = 0;
10
static uint16_t dcf_low = 0;
11
static uint8_t dcf_count = 0;
12
static uint8_t dcf_buffer[8];
13
static uint8_t dcf_last[8];
14
static volatile bool dcf_minute = false;
15
16
ISR(TIMER0_COMPA_vect)
17
{
18
  bool low = (DATA_PIN & (1<<DATA))==0;
19
  if (config.flags & (1<<DCF_INVERT_BIT))
20
    low = !low;
21
    
22
  if (low)
23
  {
24
    LED1_PORT &= ~(1<<LED1);
25
    if (dcf_state) // falling edge
26
    {
27
      dcf_state = false;
28
      dcf_low = 0;
29
    }
30
    else dcf_low++;
31
  }
32
  else
33
  {
34
    LED1_PORT |= (1<<LED1);
35
    if (!dcf_state) // rising edge
36
    {
37
      uint16_t duration = dcf_low + dcf_high;
38
      
39
      bool bit = dcf_high> config.max_zero; // max signal length for 0 (reichelt=25(0x19), conrad=38(0x26))
40
      
41
      if (duration>=MIN_GAP && duration<=MAX_GAP) // Ende der Minute
42
      {
43
        dcf_parity ^= bit;
44
        if (dcf_count==58 && dcf_ok && !dcf_parity)
45
        {
46
          if (bit)
47
            dcf_buffer[dcf_count>>3] |= (1<<(dcf_count&7));
48
          else
49
            dcf_buffer[dcf_count>>3] &= ~(1<<(dcf_count&7));
50
51
          memcpy(dcf_last, dcf_buffer, 8);
52
          // dcf_last enthält an dieser Stelle eine komplett empfangene Minute          
53
          dcf_minute = true;
54
        }
55
        dcf_count = 0;
56
        dcf_parity = false;
57
        dcf_ok = true;
58
      }
59
      else if (duration>=MIN_SEC && duration<=MAX_SEC) // Normale Sekunde
60
      {
61
        dcf_parity ^= bit;
62
        switch(dcf_count)
63
        {
64
          case 20:
65
            dcf_parity = false;
66
            if (!bit) dcf_ok = false;
67
            break;
68
          case 28:
69
            if (dcf_parity) dcf_ok = false;
70
            dcf_parity = false;
71
            break;
72
          case 35:
73
            if (dcf_parity) dcf_ok = false;
74
            dcf_parity = false;
75
            break;
76
        }
77
          
78
        if (dcf_ok)
79
        {
80
          if (dcf_count<64)
81
          {
82
            if (bit)
83
              dcf_buffer[dcf_count>>3] |= (1<<(dcf_count&7));
84
            else
85
              dcf_buffer[dcf_count>>3] &= ~(1<<(dcf_count&7));
86
          }
87
          dcf_count++;
88
        }
89
      }
90
      else
91
      {
92
        dcf_count = 0;
93
        dcf_parity = false;
94
      }
95
            
96
      dcf_state = true;
97
      dcf_high = 0;
98
    }
99
    else dcf_high++;
100
  }
101
}
102
103
void main()
104
{
105
// Interrupt alle 1/250 sec = 4ms bei 16MHz
106
  OCR0A = 249; 
107
  TIFR0 = (1<<OCF0A);
108
  TIMSK0 = (1<<OCIE0A);
109
  TCCR0A = (1<<WGM01);
110
  TCCR0B = (1<<CS02);
111
112
  while(true)
113
  {
114
    if (dcf_minute)
115
    {
116
      dcf_minute = false;
117
      // dcf_last enthält die daten
118
    }
119
  }
120
}

Die Idee: Eben kein Interrupt durch den Empfänger, das kann bei 
schlechten Bedingungen nämlich ziemlich unkontrolliert häufig auftreten. 
Stattdessen wird der Daten-Pin des Empfängers regelmäßig per 
Timer-Interrupt (alle 4ms) abgetastet und ausgewertet. Den Code habe ich 
aus einem laufenden Programm extrahiert, daher ist er ohne Gewähr und 
ohne Anspruch auf Vollständigkeit, also nur ein Diskussionsbeitrag.

von Lurchi (Gast)


Lesenswert?

Der Interrupt code, mit Interrupt alle 4 ms sieht schon viel besser aus. 
Es fehlt dort aber noch die Umwandlung vom Bitmuster in die Zeit.

Das Signal des Empfängers direkt auf einen Interrupt ist tatsächlich 
nicht gut. Besser ist es den Interrupt wirklich Zeitgesteuert 1 oder 2 
mal die Sekunden zu haben. Der Timer wird mit einer Art Software PLL an 
den Anfang der Pulse angebunden und kann damit relativ tolerant gegen 
Störungen sein. So werden nur Pulse am Anfang der Sekunde ausgewertet - 
zusätzliche Störpulse werden ignoriert, wenn sie nicht gerade in der 
interessante Zeitfenster fallen.

Das ganze ist ein Abwägung zwischen Aufwand und Empfindlichkeit gegen 
Störungen. Wenn man es weit treibt, werden auch Daten aus 2 oder 3 
Minuten ausgewertet.

von Cube_S (Gast)


Lesenswert?

Jede in einem digitalen System gespeicherte Zeit ist ein Bitmuster. Zur 
Ergänzung kann ich hier noch die Umwandlung in ein DS1307-taugliches 
Bitmuster angeben:
1
        ds1307_set[2] = ((dcf_set[2]>>5)&7)|((dcf_set[3]&15)<<3); // minute
2
        ds1307_set[3] = ((dcf_set[3]>>5)&7)|((dcf_set[4]&7)<<3); // hour
3
        ds1307_set[4] = (dcf_set[5]>>2)&7; // weekday
4
        ds1307_set[5] = ((dcf_set[4]>>4)&15)|((dcf_set[5]&3)<<4); // day
5
        ds1307_set[6] = ((dcf_set[5]>>5)&7)|((dcf_set[6]&3)<<3); // month
6
        ds1307_set[7] = ((dcf_set[6]>>2)&63)|((dcf_set[7]&3)<<6); // year
dcf_set wäre durch dcf_last aus dem letzen Schnipsel zu ersetzen. 
ds1307_set[0..1] fehlen hier, denn die sind nur für TWI (Start-Adresse) 
bzw. Sekunde verantwortlich was in diesem Zusammenhang nicht 
interessiert. Ansonsten sind die Werte BCD codiert.

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.