• Hallo Zusammen, Aufgrund der aktuellen Situation setzten wir die Möglichkeit aus, sich mit Gmail zu registrieren. Wir bitten um Verständnis Das RCMP Team

Praxisbericht DCF77 Empfang mit Arduino

BAXL

Admin
Mitarbeiter
Wie es aussieht, gibt es viele verschiedene DCF77 Module, die unterschiedlich beschaltet worden sind. Die ganz einfachen liefern nur ein schwaches Signal am Ausgang, den man noch mit einer Zusatzbeschlatung versehen muß, um diese z.B. an ein Microcontrollerboard (Arduino Raspberry usw.) an einem der Eingangsports anschließen zu können. Ebenso findet man die unterschiedlichesten Möglichkeiten eine Versorgungsspannung anschließen zu können. Auch da reicht das Spektrum von 1,2V bis 15V.

Bei Microcontrollern ist man auf der Sonnenseite, wenn die Module bereits vertärkte Ausgänge (open collector) bieten. Da braucht es idR. nur einen PullUp Widerstand am Ausgang um ein auswertbares Signal für einen Microcontroller zu bekommen. Dementsprechend sind auch die Preise. Die einfacheren Versionen erhält man schon so um die 6€. Bei den verstärkten Schaltungen landet man bei ca. 10-15€. Braucht man also ein Modul für den Arduino, kann sich die Mehrausgabe u.U. lohnen, zumal die Versandkosten die Anschaffung zusätzlich beeinflussen. Ein scheinbar günstiges Modul für um die 5€ beaufschlagen die Lieferanten gerne mit Versandkosten, die den Preis locker verdoppeln. Also sollte man sorgfältig vergleichen, weil der etwas höhere Modulpreis mit Versandkosten oft nur 2-3€ teurer ist als die billigen Module mit Versandgebühr. Darum habe ich zu dem ELV-Modul gegriffen. Die anderen müssen nicht schlechter sein, nur will ich mir den Aufwand einer Zusatzbeschaltung ersparen. Man bedenke, dass man für die Zusatzbeschaltung ebenfalls Bauteile beschaffen muß, falls man die nicht gerade im Fundus hat. In Summe also eine Erhöhung des Anschaffungspreises.

Weiterhin gibt es Module, die zwei Ausgänge anbieten, einmal einen invertierten und einen nichtinvertierten Ausgang. Sofern man das mit einem uC auswertet, kann man das softwaremäßig umdrehen. Darum kann man schlecht ein bestimmtes Modul als das Beste klassifizieren. Höchstens die technischen Daten können noch einen Einfluß haben. Das ELV-Modul soll z.B. sehr schnell ein Signal empfangen können und andere benötigen ein paar Sekunden bis Empfang vorhanden ist. Ob das allerdings wirklich ein Ausschluß- oder Kaufkriterium ist, sollte man an der praktischen Anwendung fest machen.
 

BAXL

Admin
Mitarbeiter
Kurzer Zwischenstatus:

Das DCF77 Modul von ELV ist angeschlossen und läuft. Dazu musste ich den Signalpin mit einem 10 KOhm Widerstand auf 5 V und an Digitalpin 2 vom Arduino legen, weil der Ausgang ein Open Collector ist. Zu beachten ist, dass das Signal invertiert wird und entsprechende Einstellungen im Programm nötig sind. Das passiert bei der Initialisierung:

DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, false);

Der entscheidende Punkt ist der Wert "false". Hat man einen nichtinvertierenden Ausgang (könnte bei anderen Modulen der Fall sein), muß der Wert auf "true" stehen bzw. kann man den Wert dann wohl weglassen. Jetzt muß ich aber das Beispielprogramm erst noch richtig verstehen, weil darin mehrere Librarys benötigt werden. So benötigt man die "DCF77.h" und die "TimeLib.h".

Wenn ich die Sache zerlegt und verstanden habe, mache ich dazu ein neues Thema mit Schaltplan und Beispielprogramm auf. Ich kann jetzt aber schon sagen, dass es bis hier hin einfacher war als befürchtet, man muß nur die richtigen Quellen im Internet finden, weil es unzählige Suchergebnisse gibt, in denen jeweils anders an die Sache herangegangen wurde. Das größte Problem dabei ist, die richtige Seite zu finden. Ich wiederhole mich nur ungern, aber das ist die Sache mit dem "einfachen" Kopieren von Codeschnipsel. Es wird viel geschrieben, man muß sich aber selbst noch bemühen.

Damit es nicht verloren geht, vorsichtshalber schon mal der Programmcode, der mit dem ELV-Modul und wahrscheinlich auch anderen Modulen läuft, die einen invertierten Ausgang haben.

C++:
//Beispielcode um Arduino UNO mit DCF77 Modul von ELV zu verbinden und Zeit auszulesen.
//Mutationen durch slaps313 - 2018
//DCF77.h und TimeLib.h wurden ohne Anpassungen verwendet.
//DCF77 Bibliothek wurde von hier erhalten: http://thijs.elenbaas.net/downloads/?did=1
//TimeLib.h Bibliothek wurde von hier erhalten: https://github.com/PaulStoffregen/Time
//Die Sketch-Vorlage wurde von hier geladen (hier werden auch andere Module behandelt): https://www.issb.de/mw/index.php/Test_elektronischer_Funkuhren-Module_(DCF77)_am_Mikroconcroller

#include "DCF77.h" //Alle DCF77 Funktionen laufen ueber diese Bibliothek.
#include "TimeLib.h" //Time.h hat bei mir nie funktioniert, habe TimeLib.h eingebunden, dann gehts.

#define DCF_PIN 2 // Verbindung zum DCF77 Arduino UNO PIN
#define DCF_INTERRUPT 0 // Interrupt number associated with pin
#define PIN_LED 13 // Status von der Verbindung an LED-PIN 13

//time_t time;
// DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT); // Dieser Eintrag sollte für andere Module aktiviert werden...
// für das DCF-Modul von ELV muss das Signal invertiert werden, deshalb so:
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT, false);
// wurde ein gueltiges Signal gefunden
bool g_bDCFTimeFound = false;

void setup()
{
pinMode(PIN_LED, OUTPUT);
Serial.begin(9600);
DCF.Start();
Serial.println("Warte auf DCF77 Zeit... ");
Serial.println("Es dauert in den meisten faellen mindestens 2 Minuten bis die Zeit aktualisiert wird.");
}

void loop()
{
// delay(950);
// das Signal wird nur alle 5 Sekunden abgefragt
delay(5000);

digitalWrite(PIN_LED, HIGH);
delay(50);
digitalWrite(PIN_LED, LOW);

time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
if (DCFtime != 0)
{
Serial.println("Aktuelle Zeit wurde empfangen!");
setTime(DCFtime);
g_bDCFTimeFound = true;

}

// die Uhrzeit wurde gesetzt, also LED nach kurzer Zeit ein
if (g_bDCFTimeFound)
{
delay(50);
digitalWrite(PIN_LED, HIGH);
}
digitalClockDisplay();
}

void digitalClockDisplay()
{
// Anzeigen der Zeit
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}

void printDigits(int digits)
{
// Kleines Skript um bei Minuten und Sekunden eine 0 vornean zu stellen
Serial.print(":");
if(digits < 10)
Serial.print('0');
Serial.print(digits);
}
 

BAXL

Admin
Mitarbeiter
Ich bin schon auf Deine Erkenntnisse gespannt. Läuft es denn schon, ich meine konntest Du schon eine Zeit abrufen? Willst du auch noch eine RTC dazuklemmen?
 

Quiddje

Mitglied
Ja, das DCF77 Modul soll stündlich das RTC Modul stellen.
Bisher hab ich nix empfangen. Null. Zwischendurch finde ich Drahtbrücken die nur so aussehen als würden sie stecken,
dummerweise sind die Enden abgebrochen und tut dann nicht funktionieren. Ich probiere weiter...
 
D

Deleted member 1492

Gast
Gut das ich zeitlos bin, aber interessantes Thema. Bitte weitermachen. :cool:

 
Zuletzt von einem Moderator bearbeitet:

Quiddje

Mitglied
Basis soll dieser sketch werden:

Code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "DCF77.h"
#include <TimeLib.h>
#include <DS1307RTC.h>
LiquidCrystal_I2C lcd(0x27,16,2);

byte radio_controlled[] = {
  B01110,
  B10001,
  B00100,
  B01010,
  B00000,
  B00100,
  B00100,
  B00100
};

#define DCF_PIN 2           // Pin für den DCF 77 setzen
#define DCF_INTERRUPT 0    // Interrupt Nummer, die dem Pin zugeordnet ist

time_t time;
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT,true);

int DCFupdate = 0;
int rc_char_blink = 0;

void setup() {
  Serial.begin(9600);
 
  DCF.Start();
  pinMode(DCF_PIN, INPUT);
  lcd.begin(16,02);
  lcd.createChar(0, radio_controlled);
  lcd.backlight();

  setSyncProvider(RTC.get);   // Funktion, um die Uhrzeit vom RTC zu erhalten

}

void loop() {
  digitalClockDisplay();
  DCF_auslesen();
  DCF_Display();
}

void DCF_auslesen() {
  time_t DCFtime = DCF.getTime(); // Prüfen Sie, ob eine neue DCF77-Zeit verfügbar ist
  if (DCFtime != 0)
  {
    setTime(DCFtime);
    RTC.set(now());
    DCFupdate = 1;
    lcd.clear();
  }
}

void DCF_Display() {

  if (DCFupdate == 0) { // Zeigt ein blinkendes Symbol während der Synchronisationsphase an
    rc_char_blink++;

    if (rc_char_blink < 50) {
      lcd.setCursor(15, 1);
      lcd.write(byte(0));
    }
    else {
      lcd.setCursor(15, 1);
      lcd.print(" ");
    }
    if (rc_char_blink > 100) {
      rc_char_blink = 0;
    }
  }
}

//Festlegen der Wochentage

void digitalClockDisplay() {
  lcd.setCursor(0, 1);
  switch (weekday()) {
    case 1: lcd.print("So"); break;
    case 2: lcd.print("Mo"); break;
    case 3: lcd.print("Di"); break;
    case 4: lcd.print("Mi"); break;
    case 5: lcd.print("Do"); break;
    case 6: lcd.print("Fr"); break;
    case 7: lcd.print("Sa"); break;
  }

  int mm;
  int ss = second();
  mm = minute();
  lcd.setCursor(3, 1);


  // Anzeige der Uhrzeit

  if (day() < 10) {
    lcd.print("0");
    lcd.print(day());
  }
  else lcd.print(day());

  lcd.print(".");

  if (month() < 10) {
    lcd.print("0");
    lcd.print(month());
  }
  else lcd.print(month());

  lcd.print(".");
  lcd.print(abs(year() - 2000));

  lcd.setCursor(03, 0);

  if (hour() < 10) {
    lcd.print("0");
    lcd.print(hour());
  }
  else lcd.print(hour());

  lcd.print(":");

  if (mm < 10) {
    lcd.print("0");
    lcd.print(mm);
  }
  else lcd.print(mm);

  lcd.print(":");

  if (ss < 10) {
    lcd.print("0");
    lcd.print(ss);
  }
  else lcd.print(ss);

  //if (mm == 0) { //Stündliche Synchronisation
  //  DCFupdate = 0;
  //}
}
Soweit bin ich aber noch nicht. Derzeit versuche ich überhaupt eine Uhrzeit zu bekommen.
U.a. mit deinem sketch aus #23. Oder jenem hier :

Code:
/*
 * DCFSignalQuality
 * Ralf Bohnen, 2013
 * This example code is in the public domain.
*/
#define DCF77PIN 2
void setup() {
  Serial.begin(9600);
  pinMode(DCF77PIN, INPUT);
  Serial.println("Beginne DCF77 Messung, bitte warten :");                                                       
  //Ein schlechter Empfang bedeutet nicht das wir kein Empfang haben, nur das es länger dauern würde
  //das Signal auszuwerten.
  Serial.println("KEIN SIGNAL <- |                                          <- MISERABEL <- |  SCHLECHT <- |          GUT          | -> SCHLECHT  | -> MISERABEL ->");
}
 
void loop() {
  //Führe eine Messung über 10 Impulse aus, ein Impuls dauert genau eine Sekunde
  int q = DCF77signalQuality(10);
  //Wenn kein Wechsel zwischen HIGH und LOW am Anschluss erkannt wurde
  //bedeutet das in 99,99% aller Fälle das der DCF Empfänger nicht arbeitet
  //denn bei extrem schlechten Empfang hat man Wechsel, nur kann man sie nicht auswerten.
  if (!q) {Serial.print("# (Schaltung pruefen!)");}
  for (int i = 0; i < q; i++) {
    Serial.print(">");
  }
  Serial.println("");
 
}
 
int DCF77signalQuality(int pulses) {
  int prevSensorValue=0;
  unsigned long loopTime = 10000; //Impuls Länge genau eine Sekunde
  //Da wir ja mitten in einem Impuls einsteigen könnten, verwerfen wir den ersten.
  int rounds = -1;
  unsigned long gagingStart = 0;
  unsigned long waitingPeriod = 0;
  int overallChange = 0;
  int change = 0;
 
  while (true) {
    //Unsere Schleife soll das Eingangssignal (LOW oder HIGH) 10 mal pro
    //Sekunde messen um das sicherzustellen, messen wir dessen Ausführungszeit.
    gagingStart = micros();
    int sensorValue = digitalRead(DCF77PIN);
    //Wenn von LOW nach HIGH gewechselt wird beginnt ein neuer Impuls
    if (sensorValue==1 && prevSensorValue==0) {
      rounds++;
      if (rounds > 0 && rounds < pulses + 1) {overallChange+= change;}
      if (rounds == pulses) { return overallChange /pulses;}
      change = 0;
    }
    prevSensorValue = sensorValue;
    change++;
 
    //Ein Wechsel zwichen LOW und HIGH müsste genau alle 100 Durchläufe stattfinden
    //wird er größer haben wir kein Empfang
    //300 habe ich als guten Wert ermittelt, ein höherer Wert würde die Aussage festigen
    //erhöht dann aber die Zeit.
    if (change > 300) {return 0;}
    //Berechnen und anpassen der Ausführungszeit
    waitingPeriod = loopTime - (micros() - gagingStart);
    delayMicroseconds(waitingPeriod);
  }
}
Durch den Pulsetest weiß ich ja in welchen Ecken des Raumes ich Empfang habe und wo nicht.
Den Test hab ich sowohl mit einem Operationsverstärker der eine LED betreibt, als auch mit LED und 2,7k Widerstand zwischen Signal und +5V gemacht.
Beziehungsweise mach ich das öfter mal um das Modul zu prüfen.
 

BAXL

Admin
Mitarbeiter
Hast Du mal den von mir ausprobiert, der Anschluss an Pin 2 ist der Gleiche, Du musst nur beim Initialisierungsbefehl true statt false einsetzen. Und dann guck Dir die Sache auf dem PC Monitor an. Damit stellen die Routinen für die RTC und das Display schon mal keine Fehlerquelle dar Später ginge auch der Code mit Diaplay.
 

BAXL

Admin
Mitarbeiter
Hmmm, dann scheint etwas mit der Hardware nicht zu stimmen. Wie sieht Deine Zusatzbeschaltung denn aus? Die Elektronik reagiert auch auf Störfelder empfindlich. Manchmal reicht es da achon die Position zu verändern. Ich hatte Anfangs auch Probleme mit dem Empfang, nach dem ich die Antenne nur ein paar Zentimeter verschoben hatte bekam ich die Uhrzeit.Das dauerte ca 3 Minuten.

Evtl mal einen Darlingtontransistor als open Collector mit einem Pullup Widerstand nehmen. Z.B. Einen BC 517...
 
Zuletzt bearbeitet:

Quiddje

Mitglied
Derzeit bin ich viel am Lesen über das Conradmodul.
Fast alle schließen einen 10K Widerstand zwischen Daten und +. Einige haben das nur mit 6K oder 4,7K hinbekommen. Aha.
Über einen Transistor denk ich auch nach.
Beide Module scheinen zu funktionieren:


Mal sehen, morgen wieder.
 

BAXL

Admin
Mitarbeiter
Das sieht schon gut aus, die Frage ist, ob der Arduino die Signale auswerten kann. Der braucht ja ordentliche Flanken und ein erkennbares LOW Signal um die Pausen messen zu können.
 

Quiddje

Mitglied
Ja, kenne ich. Danke fürs suchen.
Neben der Signalverarbeitung stellt sich mir die Frage wie sauber das Signal ist das in die Wohnung kommt.
Weil ja auch die gekaufte Funkuhr schwierigkeiten hat.
Ein Oszilloskop wär nicht schlecht.
Ich werd mich wohl mal mit dem Läppi auf den Balkon setzten und den arduino mit dem DCF Modul mit ner 1meter Leiste raus hängen
und den Seriellen Monitor betrachten.
Danach kümmer ich mich mal um den Widerstandswert.
Bisher hatte ich einen 10k Widerstand.
 

Quiddje

Mitglied
So, ich kann Erfolg vermelden. Heute hats geklappt - Funkzeit nach 5 Minuten.
Vorweg hab ich das mit dem Uno und einem Atmega 328 probiert. Ungefähr 12x hab ich neu verkabelt.
Auf 2 verschiedenen Steckbrettern. Drinnen und draußen probiert. Für den seriellen Monitor hab ich 7 Sketche genommen.
Zwischendurch immer wieder die DCF Module getestet.
Heute hab ich 2 Änderungen gemacht.
Als Pullup hab ein 50k Poti genommen (was 46k hat) und verschieden Werte probiert
mit folgendem Sketch:
Code:
#define DCF77PIN 2
#define POWER 7
 
unsigned char signal = 0;
unsigned char buffer;
 
void setup(void) {
 Serial.begin(9600);
 pinMode(7, OUTPUT);
 digitalWrite(7, LOW);
 pinMode(DCF77PIN, INPUT);
}
 
void loop(void) {
 signal = digitalRead(DCF77PIN);
 if (buffer != signal) {
 Serial.println(signal);
 buffer = signal;
 }
}
Auf dem seriellen Monitor sieht man eine Zahlenfolge untereinander. 0101010101010 usw.
Beziehungsweise nichts wenns kein Signal gibt.
Das Poti hab ich langsam von 5k bis 46k gedreht. Interessanterweise gab es über den gesammten Bereich mehrere Punkte
wo die Zahlenreihe lief und welche wo sie nicht lief. Dabei handelt es sich nicht um genaue Zahlen wie 20k, sondern etwas wie23,7k.
An den Punkte wo sie lief, lief sie mit unterschiedlicher Geschwindigkeit. Ich hab mich für 46k entschieden
weils da die wenigsten Störungen gab und da schien es am schnellsten zu laufen.

Folgender Sketch war auch gut, er kümmert sich um die Signalqualität, auf dem seriellen Monitor:
Code:
/*
 * DCFSignalQuality
 * Ralf Bohnen, 2013
 * This example code is in the public domain.
*/
#define DCF77PIN 2
void setup() {
  Serial.begin(9600);
  pinMode(DCF77PIN, INPUT);
  Serial.println("Beginne DCF77 Messung, bitte warten :");                                                       
  //Ein schlechter Empfang bedeutet nicht das wir kein Empfang haben, nur das es länger dauern würde
  //das Signal auszuwerten.
  Serial.println("KEIN SIGNAL <- |                                          <- MISERABEL <- |  SCHLECHT <- |          GUT          | -> SCHLECHT  | -> MISERABEL ->");
}
 
void loop() {
  //Führe eine Messung über 10 Impulse aus, ein Impuls dauert genau eine Sekunde
  int q = DCF77signalQuality(10);
  //Wenn kein Wechsel zwischen HIGH und LOW am Anschluss erkannt wurde
  //bedeutet das in 99,99% aller Fälle das der DCF Empfänger nicht arbeitet
  //denn bei extrem schlechten Empfang hat man Wechsel, nur kann man sie nicht auswerten.
  if (!q) {Serial.print("# (Schaltung pruefen!)");}
  for (int i = 0; i < q; i++) {
    Serial.print(">");
  }
  Serial.println("");
 
}
 
int DCF77signalQuality(int pulses) {
  int prevSensorValue=0;
  unsigned long loopTime = 10000; //Impuls Länge genau eine Sekunde
  //Da wir ja mitten in einem Impuls einsteigen könnten, verwerfen wir den ersten.
  int rounds = -1;
  unsigned long gagingStart = 0;
  unsigned long waitingPeriod = 0;
  int overallChange = 0;
  int change = 0;
 
  while (true) {
    //Unsere Schleife soll das Eingangssignal (LOW oder HIGH) 10 mal pro
    //Sekunde messen um das sicherzustellen, messen wir dessen Ausführungszeit.
    gagingStart = micros();
    int sensorValue = digitalRead(DCF77PIN);
    //Wenn von LOW nach HIGH gewechselt wird beginnt ein neuer Impuls
    if (sensorValue==1 && prevSensorValue==0) {
      rounds++;
      if (rounds > 0 && rounds < pulses + 1) {overallChange+= change;}
      if (rounds == pulses) { return overallChange /pulses;}
      change = 0;
    }
    prevSensorValue = sensorValue;
    change++;
 
    //Ein Wechsel zwichen LOW und HIGH müsste genau alle 100 Durchläufe stattfinden
    //wird er größer haben wir kein Empfang
    //300 habe ich als guten Wert ermittelt, ein höherer Wert würde die Aussage festigen
    //erhöht dann aber die Zeit.
    if (change > 300) {return 0;}
    //Berechnen und anpassen der Ausführungszeit
    waitingPeriod = loopTime - (micros() - gagingStart);
    delayMicroseconds(waitingPeriod);
  }
}
Der Widerstandswert war also schon mal ganz gut, es gab aber immer noch keine Funkzeit.
Dann hab ich einen Operationsverstärker in die Signalleitung gehängt, einen LM358.
Und nach 5 Minuten (in der Wohnung) war die Funkzeit da. Also alles nochmal mit 2004 und RTC aufgebaut
und ebenfalls nach 5 Minuten war die Funkzeit auf dem Display.
Wie lange hab ich nun rumgespielt? Ach will ich gar nicht wissen ...

:cool:
 
Top Bottom