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
http://www.mikrocontroller.net/search?query=DCF+code&forums[]=1&forums[]=19&forums[]=9&forums[]=10&forums[]=2&forums[]=4&forums[]=3&forums[]=6&forums[]=31&forums[]=17&forums[]=11&forums[]=8&forums[]=14&forums[]=12&forums[]=7&forums[]=5&forums[]=15&forums[]=13&forums[]=18&forums[]=16&max_age=-&sort_by_date=0 Zu dem Thema gab's schon so viel hier im Forum, die vielen Einträge will ich jetzt nicht durch einen weiteren ergänzen. Es sind massenhaft dabei, die funktionieren.
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
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.
void dcf_sync(void) { ... dcf_sync(); ... dcf_sync(); ... } Rekursiver Selbstaufruf. Naja.
holger schrieb: > Rekursiver Selbstaufruf. Naja. Autsch: Wer macht denn aber auch sowas. Ich hab nur nach Schleifen abgesucht.
>> 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;)
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
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
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.
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.
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
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.
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
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.
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
|
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.
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?
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.
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.
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.
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.
Muss ich den Pin PD2 auf Input schalten, damit ein Interrupt ausgelöst werden kann?
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.
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?
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.
Funktioniert auch. Die Led am Atmega32 blikt in der ISR Routine in einem bestimmten Rhythmus.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.