- 3D-Druck Einstieg und Tipps         
Ergebnis 1 bis 8 von 8

Thema: DCF77 - meine Lösung

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.09.2005
    Ort
    Osnabrücker Land
    Alter
    62
    Beiträge
    534

    DCF77 - meine Lösung

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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
    Code:
    #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
    Code:
    
    #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
    Code:
    #ifndef erklaerung_der_empfangenen_bits
    
    00000000000000000010100101101101010111000010101000011000001_
    00000000000000000010110101100101010111000010101000011000001_
    00000000000000000010111101101101010111000010101000011000001_
    00000000000000000010100011101101010111000010101000011000001_
    00000000000000000010110000010101010111000010101000011000001_
    00000000000000000010101000010101010111000010101000011000001_
    00000000000000000010111000011101010111000010101000011000001_
    00000000000000000010100100010101010111000010101000011000001_
    00000000000000000010110100011101010111000010101000011000001_
    00000000000000000010110010011101010111000010101000011000001_
    00000000000000000010100001010101010111000010101000011000001_
    00000000000000000010110001011101010111000010101000011000001_
    00000000000000000010101001011101010111000010101000011000001_
    00000000000000000010100101011101010111000010101000011000001_
    00000000000000000010110011010101010111000010101000011000001_
    00000000000000000010100000000011010111000010101000011000001_
    00000000000000000010110000001011010111000010101000011000001_ 
    00000000000000000010111000000011010111000010101000011000001_
    00000000000000000010100100001011010111000010101000011000001_
    00000000000000000010110100000011010111000010101000011000001_ 
    00000000000000000010100100100011010111000010101000011000001_
    
    012345678901234567890123456789012345678901234567890123456789
    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
    ____________________________________11000010101000011000001 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
    Ich kann mir keine Signatur leisten - bin selbständig!

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    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
    Disclaimer: none. Sue me.

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.09.2005
    Ort
    Osnabrücker Land
    Alter
    62
    Beiträge
    534
    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
    Ich kann mir keine Signatur leisten - bin selbständig!

  4. #4
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    07.11.2004
    Beiträge
    332
    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 ?

    Gruss Ritchie

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

  5. #5
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    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).
    Disclaimer: none. Sue me.

  6. #6
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    07.11.2004
    Beiträge
    332
    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

  7. #7
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    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...
    Disclaimer: none. Sue me.

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    02.09.2005
    Ort
    Osnabrücker Land
    Alter
    62
    Beiträge
    534

    DCF77 und UART-Debug

    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
    Code:
    #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
    Code:
    #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
    Code:
    #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;
    	}
    }
    Ich kann mir keine Signatur leisten - bin selbständig!

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress