PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : DCF77 - meine Lösung



vajk
12.02.2006, 09:20
Hallo

Ich hab viel im Netz gelesen und mir viele Codebeispiele angesehen.
(Hier die eine gute Site, die viel Informationen gibt:
http://www.heret.de/funkuhr/index.htm)


Mit einem OSZI hab ich mir dann das Empfangs-Signal mal angesehen ...
... und endlich verstanden ;-)

... jetzt weiß ich auch, warum bei so 'ner Funkuhr das Signalzeichen mal da ist, mal nicht ... Der Empfang der Zeit ist nicht immer ungestört und somit die Information nicht vollständig. Informationsperiode ist eine Minute.

Meine Lösung basiert auf folgende Vorgehensweise:

1. Ein Timer (alle ~ 2,1ms) zählt den Zähler für Minutensignal und Secsignal hoch - void dcf_timer_overflow(void) // alle ~2,1ms

2. Der Interrupt (auf beide Flanken des Impulses) entscheidet über Zählerfunktionen - void dcf_interrupt(void) // Signal vom DCF_Modul

Das alles hat den Vorteil. daß der Timer imemr normal durchlaufen kann und mehrfach benutzt werden kann (bei mir u.a. für Tastenentprellung, Erkennung Lang- und Kurzdrücken einer Taste, Auswerten von Drehimpulsgebern, ...)

3. Und wenn grad kein Interruptjob oder sonst was läuft, wird die Zeit ermittelt ... void dcf_auswertung()


Hier mein Zeh - Code :-)

Hier die Header-Datei


#ifndef _dcf77_h_
#define _dcf77_h_

typedef struct
{
byte valid;
byte MESZ;
byte min;
byte valid_min;
byte std;
byte valid_std;
byte tag;
byte wota;
byte mon;
int year;
byte valid_datum;
}DCF_TIME;

#ifdef __dcf77_h_intern_

DCF_TIME DCF_time;
long lval_dcf_store;

void dcf_Init(void);
void dcf_timer_overflow(void);
void dcf_interrupt(void);
void dcf_auswertung(void);

#else

extern DCF_TIME DCF_time;
extern long lval_dcf_store;
extern void dcf_Init(void);
extern void dcf_timer_overflow(void);
extern void dcf_interrupt(void);
extern void dcf_auswertung(void);

#endif
#endif


Und hier dier Quälcode




#include <inttypes.h>
#include <avr/io.h>
//#include <avr/signal.h>
//#include <avr/interrupt.h>
//#include <avr/delay.h>
#include <stdio.h> // für printf
//#include <stdlib.h>
#include <string.h>
//-------------------------------------------------------

#include "basdef_h"
#include "ic2twi_h.h"

#include "defines_h.h"

#define __dcf77_h_intern_
#include "dcf77_h.h"

// die folgenden Konstanten regel das Zeitfenster
const int cnt_mehrals_1secin2erms = 490; // 1000ms / 2,048 = 488,28 -> 490
const int cnt_kanpp_100msin2erms = 45; // 100 ms / 2,048 = 48,828 -> 45
const int cnt_kanpp_200msin2erms = 90; // 200 ms / 2,048 = 97,656 -> 90
byte bitbuffer[60];
byte bitauswertung[60];
int bitposition = -1;
int flag_auswertung = -1; // auswertung läuft erst ab 0
int cnt_dcf_min_zeit = -1;
int cnt_dcf_sig_zeit = -1;


void dcf_Init(void) // Grundinitialisierung bei Programmstart
{
lval_dcf_store = 0;
memset(&DCF_time, 0, sizeof(DCF_TIME));
}


void dcf_auswertung()
{
if(flag_auswertung > 0)
{
int p, sum;
memset(&DCF_time, 0, sizeof(DCF_TIME));

DCF_time.valid = 1;
for(p = 20; p < 59; p++)
{
if(bitauswertung[p] == 0)
{
DCF_time.valid = 0;
break;
}
}
if(bitauswertung[20] != 2) // immer Logisch 1
DCF_time.valid = 0;


if(DCF_time.valid)
{
DCF_time.MESZ = ((bitauswertung[17] == 1) && (bitauswertung[18] == 0));

// 21-27: 7 Bits Minute 1,2,4,8,10,20,40
DCF_time.min = (bitauswertung[21] == 2) * 1 +
(bitauswertung[22] == 2) * 2 +
(bitauswertung[23] == 2) * 4 +
(bitauswertung[24] == 2) * 8 +
(bitauswertung[25] == 2) * 10 +
(bitauswertung[26] == 2) * 20 +
(bitauswertung[27] == 2) * 40;
// 28: 1 Bit Paritiy Minute - Bit 21-27
sum = 0;
for(p = 21; p <= 28; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_min = !(sum % 2);

// 29-34: 6 Bits Stunde 1,2,4,8,10,20
DCF_time.std = (bitauswertung[29] == 2) * 1 +
(bitauswertung[30] == 2) * 2 +
(bitauswertung[31] == 2) * 4 +
(bitauswertung[32] == 2) * 8 +
(bitauswertung[33] == 2) * 10 +
(bitauswertung[34] == 2) * 20;
// 35: 1 Bit Parity Stunde - Bit 29-34
sum = 0;
for(p = 29; p <= 35; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_std = !(sum % 2);

// 36-41: 6 Bits Tag 1,2,4,8,10,20
DCF_time.tag = (bitauswertung[36] == 2) * 1 +
(bitauswertung[37] == 2) * 2 +
(bitauswertung[38] == 2) * 4 +
(bitauswertung[39] == 2) * 8 +
(bitauswertung[40] == 2) * 10 +
(bitauswertung[41] == 2) * 20;

// 42-44: 3 Bits Wochentag 1,2,4 - 1=Mo .. 7=So
DCF_time.wota =(bitauswertung[42] == 2) * 1 +
(bitauswertung[43] == 2) * 2 +
(bitauswertung[44] == 2) * 4;

// 45-49: 5 Bits Monat 1,2,4,8,10
DCF_time.mon = (bitauswertung[45] == 2) * 1 +
(bitauswertung[46] == 2) * 2 +
(bitauswertung[47] == 2) * 4 +
(bitauswertung[48] == 2) * 8 +
(bitauswertung[49] == 2) * 10;

// 50-57: 8 Bits Jahr 2005+ 1,2,4,8,10,20,40,80
DCF_time.year = (bitauswertung[50] == 2) * 1 +
(bitauswertung[51] == 2) * 2 +
(bitauswertung[52] == 2) * 4 +
(bitauswertung[53] == 2) * 8 +
(bitauswertung[54] == 2) * 10 +
(bitauswertung[55] == 2) * 20 +
(bitauswertung[56] == 2) * 40 +
(bitauswertung[57] == 2) * 80 + 2000;
// 58: Paritiy Datum - Bit 35-57
sum = 0;
for(p = 36; p <= 58; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_datum = !(sum % 2);

/*
printf("\n%02d:%02d (%d/%d) - %02d.%02d.%04d (%d)", (int)DCF_time.std, (int)DCF_time.min, (int)DCF_time.valid_std, (int)DCF_time.valid_min,
(int)DCF_time.tag, (int)DCF_time.mon, (int)DCF_time.year, (int)DCF_time.valid_datum);

23:44 (1/1) - 03.02.2006 (1)
*/
}
/*
else
{
printf("\n#");
for(int i = 0; i < 60; i++)
{
switch(bitauswertung[i])
{
case 1 : printf("0"); break;
case 2 : printf("1"); break;
default: printf("_"); break;
}
}
printf("#");
}
*/

flag_auswertung = 0;
}
}








// Bei jedem TimerZyklus wird ggf. entsp. Zähler erhöht
void dcf_timer_overflow(void) // alle ~2,1ms
{
if(cnt_dcf_min_zeit >= 0)
cnt_dcf_min_zeit++;

if(cnt_dcf_sig_zeit >= 0)
cnt_dcf_sig_zeit++;

// wenn kein Empfang ist, aber die timer gestartet wurden,
// werden sie automatisch angehalten, wenn MAXINT überschritten wurde ;-)
}

// Signal vom DCF_Modul
void dcf_interrupt(void)
{
byte SigVal = DCF77_Port & (1 << DCF77_INT); // INT - Port
if(SigVal) // Beginn der Sekunde
{
cnt_dcf_sig_zeit = 0; // Zähler für Längenmessung des Sec.Signals löschen

int store_cnt_dcf_min_zeit = cnt_dcf_min_zeit;
cnt_dcf_min_zeit = 0; // Sekundenzeitmessung neu starten

if(store_cnt_dcf_min_zeit > 0) // Sekundenzeitmessung lief
{
if(store_cnt_dcf_min_zeit > cnt_mehrals_1secin2erms) // letzter Durchgang länger als 1 sec, somit MinutenStart = neue Auswertung beginnt
{
if(flag_auswertung < 0)
flag_auswertung = 0; // ab jetzt sind Auswertungen möglich
else
{
memcpy(bitauswertung, bitbuffer, 60);
flag_auswertung = 1; // Auswertung abgeschlossen, Haupt-Loob-Job freigeben
}

// ab jetzt darf gespeichert werden
memset(bitbuffer, 0, 60); // alle Felder ohne Empfangsinformation
bitposition = 0;
}
}
}
else // Ende der Zeitmessung einer sec.
{
int store_cnt_dcf_sig_zeit = cnt_dcf_sig_zeit;
cnt_dcf_sig_zeit = -1; // Zähler aus

if((bitposition >= 0) && (bitposition < 60))
{
if(store_cnt_dcf_sig_zeit > cnt_kanpp_100msin2erms)
{
if(store_cnt_dcf_sig_zeit > cnt_kanpp_200msin2erms)
bitbuffer[bitposition] = 2; // Logische 1
else
{
bitbuffer[bitposition] = 1; // Logische 0
}
}

// im Nichtempfangsfall bleibt ArrayFeld "leer"

bitposition++;
}
}
}







Hier die empfangenen Bitfolgen mit Erklärung in Kurzform


#ifndef erklaerung_der_empfangenen_bits

00000000000000000010100101101101010111000010101000 011000001_
00000000000000000010110101100101010111000010101000 011000001_
00000000000000000010111101101101010111000010101000 011000001_
00000000000000000010100011101101010111000010101000 011000001_
00000000000000000010110000010101010111000010101000 011000001_
00000000000000000010101000010101010111000010101000 011000001_
00000000000000000010111000011101010111000010101000 011000001_
00000000000000000010100100010101010111000010101000 011000001_
00000000000000000010110100011101010111000010101000 011000001_
00000000000000000010110010011101010111000010101000 011000001_
00000000000000000010100001010101010111000010101000 011000001_
00000000000000000010110001011101010111000010101000 011000001_
00000000000000000010101001011101010111000010101000 011000001_
00000000000000000010100101011101010111000010101000 011000001_
00000000000000000010110011010101010111000010101000 011000001_
00000000000000000010100000000011010111000010101000 011000001_
00000000000000000010110000001011010111000010101000 011000001_
00000000000000000010111000000011010111000010101000 011000001_
00000000000000000010100100001011010111000010101000 011000001_
00000000000000000010110100000011010111000010101000 011000001_
00000000000000000010100100100011010111000010101000 011000001_

01234567890123456789012345678901234567890123456789 0123456789
0 1 2 3 4 5
_________________Z1 17: MEZ = 0 MESZ = 1 => 0 = MEZ
__________________Z2 18: MEZ = 1 MESZ = 0 => 1 = MEZ
____________________X 20: immer 1 => 1 o.k.
_____________________mmmmmmm
_____________________0010010 = 2+10=12
____________________________Pm
____________________________0 Summe 2 o.k.
_____________________________hhhhhh
_____________________________011010 = 2+4+10=16
___________________________________Ph
___________________________________1 Summe 4 o.k.
____________________________________dddddd
____________________________________110000 = 1+2=3 o.k.
__________________________________________www
__________________________________________101 = 1+4=5 = Fr. o.k.
_____________________________________________mmmmm
_____________________________________________01000 = 2 = Feb. o.k.
__________________________________________________ yyyyyyyy
__________________________________________________ 01100000 = 2+4=6 = 2006
__________________________________________________ ________Py
____________________________________11000010101000 011000001 Summe = 8 o.k.

// 21-27: 7 Bits Minute 1,2,4,8,10,20,40
// 28: 1 Bit Paritiy Minute - Bit 21-27
// 29-34: 6 Bits Stunde 1,2,4,8,10,20
// 35: 1 Bit Parity Stunde - Bit 29-34
// 36-41: 6 Bits Tag 1,2,4,8,10,20
// 42-44: 3 Bits Wochentag 1,2,4 - 1=Mo .. 7=So
// 45-49: 5 Bits Monat 1,2,4,8,10
// 50-57: 8 Bits Jahr 2005+ 1,2,4,8,10,20,40,80
// 58: Paritiy Datum - Bit 36-57
// 59: nichts, Minutenende-Absenkung
//
// even parity .. ergänzen auf gerade anzahl bits

#endif


Vorteil durch Übergabearray - alles schön Übersichtlich fürs Verständnis ...

Einen "Fehler" hat meine Auswertung noch, meine Uhr wird nicht genau auf Sekunden eingestellt ... das mach ich noch, wenn ichs brauch.

Viel Spaß damit
Vajk

SprinterSB
13.02.2006, 09:39
Noch als Tip:

-- Du kannst deutlich Platz sparen, wenn du nicht ganze Bytes abspeicherst, sondern nur die Bits. Deine dcf_time_t Struktur kannst du als Bitfields machen, und mit den empfangenen Bits überlagern.
-- In den AVR-Headern gibt es ein <avr/parity.h>, mit dem man die Parität einfach prüfen kann.

Bei Problemen mit DCF-Ampfang:
-- Keine Schaltnetzteile als Netzteil verwenden oder Schaltung erden.
-- Keine Monitore/TFTs in der Nähe

vajk
13.02.2006, 10:08
Hallo Georg-Johann,
Danke für den Tip.
Bitfelder sind mir geläufig, ich habe nur bewust (beim mega128 gibts so schnell kein Platzproblem) darauf verzichtet, damit die Empfangsdaten leicht (via printf Ausgabe über Serielle) sichtbar gemacht werden können.

Denke das dient auch zusätzlich zum Verständnis.

Die parity.h kannt ich noch nicht, danke.

Meine Vorgehensweise bzgl. besser Empfang ist das Absetzen der DCF-77 -Einheit (Modul von Conrad), da mein Tisch sowohl Monitor, als auch HF-verseucht (Handy, KW, UKW) ist :-)

Liebe Grüße,
Vajk

Ritchie
13.02.2006, 11:39
Hallo Vajk,

das mit der Spannungsversorgung kann ich nur bestätigen.
Ich hatte, bedingt durch ein Schaltnetzteil. wilde Impulse, erzeugt durch die DCF Platine (Conrad).

Hier hat nur eine Filterung (bessere Gnd) + Kondensatoren und andere Platzierung weiter geholfen.

Ic habe aber auch den Eindruck, das die ganze Sache leicht wetterabhänig ist.

Kann mir das jemand bestätigen ? :-s

Gruss Ritchie

P.S.: Ich steuere meine DCF Karte über Interrupt (Portänderung) und einer generellen Timer Variable an.

SprinterSB
13.02.2006, 12:52
Wetter- und tageszeitabhängigkeit ist in dem Wellenlängenbereich zu erwarten.

Schaltnetzteile hab ich bisher nicht so weit entstört bekommen, daß ein DCF-Modul dahinter funktioniert. Egel wie ich Entstördrosseln und -kondensatoren dimensioniere: keine Chance. Das einzige, was hilft (und hässlich ist), ist Erdung.

Oder Netzteil selber bauen...

Hat jemand nen Tipp, wie ich ein gekauftes Stecker-Schaltnetzteil richtig entstöre? (Ohne zu es zu erden).

Ritchie
13.02.2006, 20:29
Hallo SprinterSB,

ich verwende das Netzteil von http://www.embedit.de/ (5V / 2 A) und habe eigentlich nur geringe Probleme )bei reiner ohmischer Last.

Motoren werden direkt vom Akku versorgt.

Ich benötigte Kondensatoren in der gesamten Versorgung (100nF), was die Sache sehr störungsfrei machte 5mV Brumm derzeit.

Gruss Ritchie

SprinterSB
14.02.2006, 09:19
Und das ist ein nicht-geerdetes Schaltnetzteil?

Ich denk, ich bau das selber. Da weiß ich, was ich hab und muss mich nicht mit Klump rumärgern, den man nicht entstört bekommt.

Das Problem mit SNTs scheinen nicht der Spannungsripple zu sein (den bekommt man mit Kondensatoren einfach weg), sondern daß die gesamte Sekundärseite im E-Feld schwingt. Und da würde eben nur Erdung helfen...

vajk
25.11.2007, 22:28
Nachdem mein "alter" Code nicht auf einem Pollin - ATmega32 - Board lief, habe ich diesen nun neu geschrieben ...
.. hier was fertiges inkl. Demoprogramm, Uhrzeit wird über Com1 ausgegeben.

Zur Info, hab noch Fehlerzähler implementiert ... und die Sekunden sind nun auch möglich. Uhrzeit dann fehlerfrei wenn Fehler == 0 && valid :-)

Der Code ist absichtlich nicht auf Größe optimiert, verwendet also immer noch keine Bitfelder ... C für Beginners ist schon schwer genug, so bleibts lesbarer.

Viel Spaß beim Testen,
Vajk

Demo.c


#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define __STDIO_FDEVOPEN_COMPAT_12 // fuer uart_putchar
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "basdef_h.h"

//-------------------------------------------------------
// Source-Modues
#include "dcf77_h.h"

//-------------------------------------------------------
// prototypes
static void avr_init(void);

// avrdude -P /dev/ttyS0 -p m32 -c ponyser -U f:w:demo2.hex:i -F
// ^^ avrdude-sequenz für Pollin Board, das über die serielle
// via avrdude programmiert wird, unter SIDUX / DEBIAN
// Quelle: http://www.mobile-roboter.org/content/view/13/43/


#define USEUART


//-------------------------------------------------------

byte flag_INT1 = 0;
byte old_std = 0;
byte old_min = 0;
byte old_sec = 0;
byte old_fehlcnt = 0;
byte old_rxdatafehl = 0;

#ifdef USEUART

// Gibt printf-daten auf die UART0 aus 9600 8 N1
// fdevopen(uart_putchar, NULL, 0); // 4 debugging -> use printf :-)
//-------------------------------------------------------
int uart_putchar(char c)
{
// if(c == '\n') uart_putchar('\r'); Zeilenvorschunb und Wagenrücklauf

loop_until_bit_is_set(UCSRA, UDRE);

UDR = c;

return 0;
}
#endif

//-------------------------------------------------------
int main(void)
{
avr_init();

#ifdef USEUART
fdevopen(uart_putchar, NULL, 0); // 4 debugging -> use printf :-)
printf("\nProgrammstart");
#endif

for(;;)
{
dcf_auswertung();

if(old_showdcf77sig != showdcf77sig)
{
old_showdcf77sig = showdcf77sig;

if(showdcf77sig)
PORTD |= (1 << PD5); // Licht an
else
PORTD &=~(1 << PD5); // Licht aus
}

if(DCF_time.valid) // sind die DCF - Daten überhaupt plausibel
{
if(DCF_time.valid_min && DCF_time.valid_std) // Stunden und Minuteninformation auch
{
// dann darf auch ausgewertet werden
// DCF_time.MESZ laß ich erstmal ausßen vor

// nur einmal ausgeben ...
if((DCF_time.std != old_std) || (DCF_time.min != old_min) || (DCF_time.sec != old_sec))
{
old_std = DCF_time.std;
old_min = DCF_time.min;
old_sec = DCF_time.sec;

#ifdef USEUART
printf("\n%02d:%02d:%02d %s", (int)DCF_time.std,
(int)DCF_time.min,
(int)DCF_time.sec,
DCF_time.MESZ ? "MESZ" : "MEZ");

if(DCF_time.valid_datum)
{
printf(" %02d.%02d.%04d", (int)DCF_time.tag, (int)DCF_time.mon, DCF_time.year);
}

// wota Mo=1 .. So=7 nicht berücksichtigt

if(DCF_time.fehlcnt || DCF_time.rxdatafehl)
printf(" Fehlbits: %02d / %02d", (int)DCF_time.fehlcnt, (int)DCF_time.rxdatafehl);
#endif

if((DCF_time.std >= 9) && (DCF_time.std <= 22))
PORTD |= (1 << PD6); // Licht an
else
PORTD &=~(1 << PD6); // Licht aus
}
}
}
#ifdef USEUART
else
{
if(DCF_time.fehlcnt || DCF_time.rxdatafehl)
{
if((DCF_time.fehlcnt != old_fehlcnt) || (DCF_time.rxdatafehl != old_rxdatafehl))
{
old_fehlcnt = DCF_time.fehlcnt;
old_rxdatafehl = DCF_time.rxdatafehl;

printf("\nFehlbits: %02d / %02d", (int)DCF_time.fehlcnt, (int)DCF_time.rxdatafehl);
}
}
}
#endif


if(flag_INT1 == 1)
{
flag_INT1 = 2; // durch diese "technik" ist beliebig lang Zeit, auf den Tastendruck zu reagieren
// ein einfaches ++ würde im Interrupt selbst stehen

#ifdef USEUART
printf("\n----- Taste2 ----- ");

// serielle Ausgabe dauert ja etwas .. 6 Byte = 48 Bit + 6 Bit = 5,6 ms bei 9600 BitspSec

#endif // außerdem ist die ser.Datenübertragung nicht synchron

flag_INT1 = 0;
}
}

return(0); // wird nie erreicht, da endlos for-schleife, aber weglassen führt zu compilerfehler
}

//-------------------------------------------------------
static void avr_init(void)
{
// Gedächtnisstütze :-) of 4 copy & paste
// DDRp [A,B,..] = Datenrichtungsregister Bit gesetzt = Ausgang, sonst Eingang
// PORTp = Datenregister Ausgänge setzen, wenn als Eingang definiert, dann int. Pullup mit 1 aktiviert
// PINp = Eingangsadresse - Abfrage der Eingänge
// Einzelne Bits mit (1 << x) mit x = [0..7]
// Port an mit PORTp |= (1 << x)
// Port aus mit PORTp &=~ (1 << x)

// first: alles als Eing�ge
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0;

DDRB |= (1 << PB0) | (1 << PB1); // PB0,1 als Ausgänge
DDRD |= (1 << PD5) | (1 << PD6);

// Interrupts mega128: S. 87 mega32: S. 66

// INT0 = PD2
// DCF-INT0 Taster2 INT1
MCUCR = (1 << ISC00) | (1 << ISC11); // INT0 - DCF77, both edges
GICR = (1 << INT0) | (1 << INT1); // INT0 aktivieren

// Timer mega32: S. 80
// 8Bit - Timer bei 16 MHz
// für DCF overflowerkennung alle ~2,1ms
// 16 Mhz -> 2ms ist /1024 / 32
// also CTC0 und Teiler durch 1024
// TCCR0 = (1 << WGM01) | (1 << CS00) | (1 << CS02);
// OCR0 = 32;
// TIMSK |= (1 << OCIE0); // OutputCompareMatchInterrupt Enable TOIE0); // Timer Interrupt -> 8 Bit -> Overflow bei 256
// oder via Timer 2
// 1 / 16 Mhz * 256 * 128 = 2,048 ms
TCCR2 = (1 << CS22) | (1 << CS20);
TIMSK |= (1 << TOIE2);

dcf_Init();

// serielle Kommunikation aktiveren
#ifdef USEUART
// UCSRB |= (1 << RXEN) | (1 << RXCIE); // TXEN=TX an, RXEN=RX an, RXCIE=RXcomplete Int, TXCIE=TXdto.
UCSRB |= (1 << TXEN); // | (1 << TXCIE); // TXEN=TX an, RXEN=RX an, RXCIE=RXcomplete Int, TXCIE=TXdto.
UCSRC |= (1 << USBS) | (3 << UCSZ0); // asyncron 8N1
UBRRH = 0;
#define USART_BAUD_RATE 9600
#define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*16l)-1)
UBRRL = (unsigned char) USART_BAUD_SELECT;
// UBRRL = 51; // 103 fr 9600 || 51 fr 19200 || 25 fr 38400
// 16 fr 57,6k || 12 fr 76,8k || 8 fr 115,2k - alles bezogen auf 16 MHz
#endif

sei(); // enable interrupts -> Global enable interrupt
}

//-------------------------------------------------------
// // grmpf SIGNAL(SIG_OVERFLOW0) // derzeit mit Teiler 128 -> alle ~2,1ms
// SIGNAL(SIG_OUTPUT_COMPARE0)// Compare T=255 und Vort.256 -> alle 4,08 ms
SIGNAL(SIG_OVERFLOW2)
{
uint8_t tmp_sreg = SREG;
cli(); // Interrupts aus

dcf_timer_alle2ms048();

SREG = tmp_sreg; // besser als sei(); -> Interrupts an
}

//-------------------------------------------------------
SIGNAL(SIG_INTERRUPT0) // Impuls via DCF77
{
uint8_t tmp_sreg = SREG;
cli(); // Interrupts aus

dcf_interrupt();

SREG = tmp_sreg; // besser als sei(); -> Interrupts an
}

//-------------------------------------------------------
SIGNAL(SIG_INTERRUPT1) // Taster 2
{
if(!flag_INT1) // wenn semaphore noch nicht gesetzt
flag_INT1 = 1; // na dann setzen
}


dcf77.h


#ifndef _dcf77_h_
#define _dcf77_h_

#define INPORT_INT PIND
#define PIN_INT PD2

typedef struct
{
byte valid;
byte MESZ;
byte sec;
byte min;
byte valid_min;
byte std;
byte valid_std;
byte tag;
byte wota;
byte mon;
int year;
byte valid_datum;
byte fehlcnt;
byte rxdatafehl;
}DCF_TIME;

#ifdef __dcf77_h_intern_

byte dcf77modulaktiv = 0;
byte showsigdcf77aktiv = 0;
byte old_showdcf77sig = 255;
byte showdcf77sig = 0;


DCF_TIME DCF_time;
long lval_dcf_store;

void dcf_Init(void);
void dcf_timer_alle2ms048(void);
void dcf_interrupt(void);
void dcf_auswertung(void);

#else

extern byte dcf77modulaktiv;
extern byte showsigdcf77aktiv;

extern byte showdcf77sig;
extern byte old_showdcf77sig;

extern DCF_TIME DCF_time;
extern long lval_dcf_store;
extern void dcf_Init(void);
extern void dcf_timer_alle2ms048(void);
extern void dcf_interrupt(void);
extern void dcf_auswertung(void);

#endif
#endif


dcf77.c


#include <inttypes.h>
#include <avr/io.h>
//#include <avr/signal.h>
//#include <avr/interrupt.h>
//#include <avr/delay.h>
#include <stdio.h> // fr printf
//#include <stdlib.h>
#include <string.h>
//-------------------------------------------------------

#include "basdef_h.h"

#define __dcf77_h_intern_
#include "dcf77_h.h"

byte bitbuffer[60];
byte bitauswertung[60];

int flag_auswertung = -1; // auswertung läuft erst ab 0
int bitposition = 0;
int zeitzaehler = 0;
byte signalrx = 0;
byte datavalue = 0;
byte rxdatafehl = 0;
byte store_rxdatafehl = 0;

void dcf_Init(void)
{
lval_dcf_store = 0;
memset(&DCF_time, 0, sizeof(DCF_TIME));
}

void dcf_timer_alle2ms048(void) // alle 2.048ms
{
zeitzaehler++;

// zaehlwert zw. 50ms und 100 ms bei 2.048ms = 24 .. 48 --- gewaehlt 0x020 = ~ 65ms
// zaehlwert zw.100ms und 200 ms bei 2.048ms = 48 .. 96 --- gewaehlt 0x040 = ~ 131ms
// zaehlwert > 200ms bei 2.048ms = > 96 --- gewaehlt 0x064 = ~ 205ms
// zaehlwert ~ 1060ms bei 2.048ms = 520 --- gewaehlt 0x208 = ~1065ms

byte SigVal = INPORT_INT & (1 << PIN_INT); // INT - Port
if(zeitzaehler == 0x20) // also Abtastaung mitten im 0-Bit
{
if(SigVal) // hier muß immer ein Signal sein 1..58 sec-Datenzeitbereich
{
signalrx = 1;
datavalue = 1; // Logisch 0
}
else
rxdatafehl++;
}
if(zeitzaehler == 0x40) // also Abtastung mitten im 1-Bit-Datenzeitbereich
{
if(SigVal && signalrx)
datavalue = 2; // Logisch 1
}
if(zeitzaehler == 0x64) // also Abtastung nach dem Datenzeitbereich
{
if(!SigVal && signalrx && datavalue) // kein Signal mehr, empfang und dataval
{
if(bitposition < 59)
{
bitbuffer[bitposition] = datavalue;
bitposition++;
datavalue = 0;
signalrx = 0;
DCF_time.sec++;
DCF_time.sec = (DCF_time.sec < 60) ? DCF_time.sec : 60; // 60 nicht valid
}
}
}
if(zeitzaehler == 0x208) // wird nur erreicht, wenn 59 sec = leerübermittlung oder empfangsstörung
{
if(!SigVal) // kein Signal
{
store_rxdatafehl = rxdatafehl; // Empfangsfehlerzaehler
memcpy(bitauswertung, bitbuffer, 60); // Datenbereich uebertragen
flag_auswertung = 1; // Zeitsequenz empfangen - Auswertung freigeben
}

// Neustart des Puffer
memset(bitbuffer, 0, 60); // alle Felder ohne Empfangsinformation
bitposition = 0;
DCF_time.sec = 0;
rxdatafehl = 0;
}
// 8.4 sec kein Signal ... groesser muß der zaehler nicht werden, 0 abba auch nicht
zeitzaehler = (zeitzaehler > 0x1000) ? 0x1000 : zeitzaehler;
}

void dcf_interrupt(void) // via Interrupt beide Flanken
{
byte SigVal = INPORT_INT & (1 << PIN_INT); // INT - Port
if(SigVal) // also Beginn eines Datenbits
zeitzaehler = 0;

// für die Anzeige des DCF77-Signals
showdcf77sig = SigVal; // !showdcf77sig;
}




void dcf_auswertung()
{
if(flag_auswertung > 0)
{
int p, sum;
memset(&DCF_time, 0, sizeof(DCF_TIME));

DCF_time.rxdatafehl = store_rxdatafehl;
DCF_time.valid = 1;
DCF_time.fehlcnt = 0;

for(p = 20; p < 59; p++)
{
if(bitauswertung[p] == 0)
DCF_time.fehlcnt++;
}

if(DCF_time.valid && (bitauswertung[20] != 2)) // Startbit der Zeitinformation = immer Logisch 1
DCF_time.valid = 0; // Startbit fehlt

if(DCF_time.valid)
{
DCF_time.MESZ = ((bitauswertung[17] == 1) && (bitauswertung[18] == 0));

// 21-27: 7 Bits Minute 1,2,4,8,10,20,40
DCF_time.min = (bitauswertung[21] == 2) * 1 +
(bitauswertung[22] == 2) * 2 +
(bitauswertung[23] == 2) * 4 +
(bitauswertung[24] == 2) * 8 +
(bitauswertung[25] == 2) * 10 +
(bitauswertung[26] == 2) * 20 +
(bitauswertung[27] == 2) * 40;
// 28: 1 Bit Paritiy Minute - Bit 21-27
sum = 0;
for(p = 21; p <= 28; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_min = !(sum % 2);
if(DCF_time.min > 59)
DCF_time.valid_min = 0;

// 29-34: 6 Bits Stunde 1,2,4,8,10,20
DCF_time.std = (bitauswertung[29] == 2) * 1 +
(bitauswertung[30] == 2) * 2 +
(bitauswertung[31] == 2) * 4 +
(bitauswertung[32] == 2) * 8 +
(bitauswertung[33] == 2) * 10 +
(bitauswertung[34] == 2) * 20;
// 35: 1 Bit Parity Stunde - Bit 29-34
sum = 0;
for(p = 29; p <= 35; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_std = !(sum % 2);
if(DCF_time.std > 23)
DCF_time.valid_std = 0;

// 36-41: 6 Bits Tag 1,2,4,8,10,20
DCF_time.tag = (bitauswertung[36] == 2) * 1 +
(bitauswertung[37] == 2) * 2 +
(bitauswertung[38] == 2) * 4 +
(bitauswertung[39] == 2) * 8 +
(bitauswertung[40] == 2) * 10 +
(bitauswertung[41] == 2) * 20;

// 42-44: 3 Bits Wochentag 1,2,4 - 1=Mo .. 7=So
DCF_time.wota =(bitauswertung[42] == 2) * 1 +
(bitauswertung[43] == 2) * 2 +
(bitauswertung[44] == 2) * 4;

// 45-49: 5 Bits Monat 1,2,4,8,10
DCF_time.mon = (bitauswertung[45] == 2) * 1 +
(bitauswertung[46] == 2) * 2 +
(bitauswertung[47] == 2) * 4 +
(bitauswertung[48] == 2) * 8 +
(bitauswertung[49] == 2) * 10;

// 50-57: 8 Bits Jahr 2005+ 1,2,4,8,10,20,40,80
DCF_time.year = (bitauswertung[50] == 2) * 1 +
(bitauswertung[51] == 2) * 2 +
(bitauswertung[52] == 2) * 4 +
(bitauswertung[53] == 2) * 8 +
(bitauswertung[54] == 2) * 10 +
(bitauswertung[55] == 2) * 20 +
(bitauswertung[56] == 2) * 40 +
(bitauswertung[57] == 2) * 80 + 2000;
// 58: Paritiy Datum - Bit 35-57
sum = 0;
for(p = 36; p <= 58; p++)
sum += (bitauswertung[p] == 2);
DCF_time.valid_datum = !(sum % 2);
if((DCF_time.tag > 31) || (DCF_time.tag == 0) ||
(DCF_time.wota > 7) ||
(DCF_time.mon > 12) || (DCF_time.mon == 0))
{
DCF_time.valid_datum = 0;
}

/*
printf("\n%02d:%02d (%d/%d) - %02d.%02d.%04d (%d)", (int)DCF_time.std, (int)DCF_time.min, (int)DCF_time.valid_std,
(int)DCF_time.valid_min, (int)DCF_time.tag, (int)DCF_time.mon,
(int)DCF_time.year, (int)DCF_time.valid_datum);
23:44 (1/1) - 03.02.2006 (1)
*/
}
/*
else
{
printf("\n#");
for(int i = 0; i < 60; i++)
{
switch(bitauswertung[i])
{
case 1 : printf("0"); break;
case 2 : printf("1"); break;
default: printf("_"); break;
}
}
printf("#");
}
*/

flag_auswertung = 0;
}
}