[such Hilfe] SNTP Zeitserver mit DCF77 Funkuhr

Wie im Titel zu lesen ist, versuche ich einen SNTP Zeitserver zu realisieren, der eine DCF77 Funkuhr besitzt um sich selbst nach zu stellen. Später soll der Arduino mit der DCF77 Funkuhr per PoE versorgt werden, so das er überall angebracht werden kann, wo eine Netzwerkverbindung vorhanden ist.

Meine primäre Hardware:

  • Arduino Ethernet Board (UNO und MEGA mit Ethernet Shield2 sind aber auch vorhanden).
  • DCF77 Modul von Conrad, Pollin und noch zwei weitere vorhanden.
    Meine optionale Hardware:
  • i2c Display 128x32 Pixel
  • i2c RTC DS3231.
  • SPI SD-Card Modul

Ich hab mich nun eine Woche durch diverse Foren gelesen und alle möglichen Beispiele ausprobiert.
Leider waren sie entweder nicht kompatibel oder so abstrakt das ich sie nicht verstanden habe.
Kurz und knapp, ich hab keines dazu gebracht auch nur annähernd die richtige Uhrzeit an zu zeigen.
Mein bestes Ergebnis war 04:65:00 11.04.2001 und das war heute. :wink:

Kann mir jemand bei folgenden dingen helfen?

  • Eine DCF Library zu finden, die zur aktuellen IDE 1.8.10 kompatibel ist.
    Besonders im Bezug auf time_t sowie die Time.h der IDE.
  • Ein Ethernet Beispiel zu finden in dem mit HTML Dateien auf SD-Karte gearbeitet wird aber auch
    Eingabefelder und Buttons verwendet werden um z.b. die Arduino IP per Browser zu ändern.
    ---Optional---
  • Ein Beispiel zu finden das die DCF77 Zeit in einen DS3231 übergeben kann.
    Das sind ja leider unterschiedliche Formate.

Wie ich Display, RTC und SD verwende hab ich soweit schon raus.
Nur das mit dem DCF77 und den HTML Dateien von SD bekomm ich einfach nicht zum laufen.

Ich würde mich über ein par Links oder Denkanstöße sehr freuen.

Gruß

avoid:
...
Wie ich Display, RTC und SD verwende hab ich soweit schon raus.
Nur das mit dem DCF77 und den HTML Dateien von SD bekomm ich einfach nicht zum laufen.

Ich würde mich über ein par Links oder Denkanstöße sehr freuen.

Gruß

Könntest Du Deine(n) Sketch(e) posten? Ich schlage mich gerade mit einer DS1307 herum und möchte etwas abgucken.

Zu Deinen Fragen fällt mir beim Durchstöbern Deines Codes bestimmt auch etwas ein :slight_smile:

Gruß

Gregor

PS: Wozu eigentlich zwei RTCs?

---zur Realtime Clock---
Klar, ich verwende diese Library und deren Beispiele.

Da findest du sicher was du brauchst.
Besonders gefällt mir das Wiki dazu in dem die Befehle beschrieben werden.

Warum zwei RTCs? das war nur ein Hinweis, das ich zwei verschiedene habe.
Aber das hätte ich mir sparen sollen, ist ja der selbe Chip.
Ich editiere das mal, damit die Frage nicht nochmal auf kommt.

---zur DCF77 Funkuhr---
Einen Sketch kann ich gerade nicht posten weil ich mich in Sachen DCF77 noch immer mit den Beispielen der diversen Library's rum schlage und nichts klappt. Darum bitte ich ja um einen Link zu einer Library die auch mal funktioniert und nicht nur Fehler beim hochladen verursacht oder läuft aber fehlerhaft auswertet.

Am besten hat bisher diese Library funktioniert.

Ich wohne gerade mal 30min vom DCF Sender entfernt und es dauert trotz des guten Signal über eine Stunde bis mal eine Minute gültig empfangen wurde (zumindest laut Prüfsumme) doch selbst dann ist die empfangene Zeit und das Datum alles andere als richtig, wie im Eröffnungsbeitrag beschrieben.

---zu Ethernet und SD---
Um eine HTML Datei von SD-Karte zu laden und über Port 80 dem Browser bereit zu stellen, verwende ich dieses Beispiel.

Nun geht es aber darum ein Konfigurationsmenü im HTML Format bereit zu stellen und auf Eingaben wie z.b. einen SAVE Button zu reagieren.
Die Einstellungen die per Browser gemacht wurden also zu empfangen und in einer Datei auf der SD-Karte zu speichern um beim Neustart diese wieder zu laden.

avoid:
Ich wohne gerade mal 30min vom DCF Sender entfernt und es dauert trotz des guten Signal über eine Stunde bis mal eine Minute gültig empfangen wurde (zumindest laut Prüfsumme) doch selbst dann ist die empfangene Zeit und das Datum alles andere als richtig, wie im Eröffnungsbeitrag beschrieben.

Sieh Dir mal http://www.hjberndt.de/soft/arddht11.html an. Dort geht es zwar um das Auslesen eines DHT11, aber vom Prinzip her ist das DCF-Signal ja ähnlich. Evtl. kannst Du die Auswertung des DCF-Signals ja so wie dort „zu Fuß“ erledigen. Dann brauchst Du zumindest dafür keine Bibliothek bzw. kannst Dir Deine eigene schreiben.

Gruß

Gregor

Zu DCF77 scheint hier jemand eine lauffähige Version gebaut zu haben.
Schlüssel wird die TimeLib von Paul Stoffregen sein.

Wenn Du Deine Zeit erfolgreich synchronisiert hast, kannst Du ja problemlos mit hour() usw. die DS3231 stellen.

Gruß Tommy

@gregorss
Hast du meine Gedanken gelesen? Ich bin gerade dabei eine eigene Bibliothek zu schreiben.
Hab noch einen alten Basic Code von vor 10 Jahren der damals sauber lief und den ich gerade versuche zu adaptieren.

Danke für den Link, ich habe dort diese Seite gefunden Rheinturmfunkuhr mit Arduino (Funkuhr DCF77)
Leider verwendet er hier die selbe Library wie ich oben gepostet habe. Die ist nun schon an die 5 Jahre alt und macht mit der aktuellen IDE und deren Time.h nur Probleme.
Aber ich werde schon einen Weg finden …

@Tommy56
Danke für den Tipp. also nur die TimeLib.h von Paul, werde ich mal versuchen.
Trotzdem würde ich lieber die Time.h von Arduino verwenden und was fehlt wie z.b. "now();" extra einbinden.
Wird schon schief gehen.

---nachtrag---
@Tommy56, unglaublich aber es geht.
Mit den Librarys aus deinem Link funktioniert es ohne Probleme. Nichts doppelt deklariert oder unbekannt. :wink:
Es fehlen nur ein par kleine Rückmeldungen, ein bis zwei Minuten zu warten ohne zu sehen ob sich überhaupt was tut ist nichts für mich.
Bei der Gelegenheit sehe ich auch mal, ob ich etwas an den 540Byte Ram Verbrauch optimieren kann.
sonst wird das nix wenn Ethernet, SD, RTC und Display dazu kommen.

Ich kann diese Seite sehr empfehlen incl Stoff und Lib für den Arudino
>HIER<

Gruß
DerDani

avoid:
Bei der Gelegenheit sehe ich auch mal, ob ich etwas an den 540Byte Ram Verbrauch optimieren kann.
sonst wird das nix wenn Ethernet, SD, RTC und Display dazu kommen.

Bastle doch mal eine vorzeigbare Version Deines jetzigen Sketches - Du kannst ihn ja vorher aufhübschen, falls es Dir sonst zu „peinlich“ ist.

Was den Speicherverbrauch angeht, lässt sich fast immer etwas optimieren.

Gruß

Gregor

Hier ein Teil meines geplanten Code.
Der Arduino syncronisiert sich per DCF77 und soll die Zeit auf dem Display ausgeben.
Leider bekomme ich die uint8_t nicht in char oder string gewandelt.

#include <U8g2lib.h>     // https://github.com/olikraus/u8g2
#include <Wire.h>        // für i2c (Display/RTC)
#include <DCF77.h>       // https://www.arduinolibraries.info/libraries/dcf77
#include <TimeLib.h>     // https://github.com/PaulStoffregen/Time

U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);
// 5x "u8g2_font_pixelle_micro_tr"
// 7x "u8g2_font_profont11_tr"
// 7x "u8g2_font_finderskeepers_tr"
// 10x "u8g2_font_crox2tb_tr"
// 12x "u8g2_font_helvB12_tr"

#define DCF_PIN 3         // muss interrupt fähig sein
time_t time;
time_t DCFtime = 0;
DCF77 DCF = DCF77(DCF_PIN,digitalPinToInterrupt(DCF_PIN));
bool dcfSyncNowMSG = true;
bool dcfSyncOK = false;

void setup() {
 Serial.begin(9600);
 u8g2.begin();
 u8g2.setFont(u8g2_font_finderskeepers_tr);
 showScreen(1,"Willkommen");
 DCF.Start();
 delay(1000);
}

void loop() {
  if (!dcfSyncOK){
	  if (DCFtime!=0) {
      u8g2.clearBuffer();
      showScreen(1,"DCF Sync. OK");
	  	digitalClockDisplay(DCFtime);
      dcfSyncOK = true;
	  }
    else{
      DCFtime = DCF.getTime();
      if (dcfSyncNowMSG){
        u8g2.clearBuffer();
        showScreen(1,"DCF Sync. ...");
        dcfSyncNowMSG = false;
      }
    }
    delay(1000);
  }
}

void showScreen(int line, char msg[]) {
  if (line == 1){
    u8g2.drawStr(0,8,msg); // (1-128,1-32,"")
  }
  if (line == 2){
    u8g2.drawStr(0,16,msg);
  }
  if (line == 3){
    u8g2.drawStr(0,24,msg);
  }
  if (line == 4){
    u8g2.drawStr(0,32,msg);
  }
  u8g2.sendBuffer();
}

void digitalClockDisplay(time_t _time){
  tmElements_t tm;   
  breakTime(_time, tm);
  u8g2.clearBuffer();
  // ab hier ist noch Nachbesserung angesagt
  char timeString[17];
  strcpy(timeString, "Uhrzeit: ");
  strcat(timeString, tm.Hour);
  strcat(timeString, ":");
  strcat(timeString, printDigits(tm.Minute));
  strcat(timeString, ":");
  strcat(timeString, printDigits(tm.Second));
  Serial.println(timeString);
  showScreen(1,timeString);
  char dayString[17];
  strcpy(dayString, "Datum: ");
  strcat(dayString, tm.Day);
  strcat(dayString, ".");
  strcat(dayString, tm.Month);
  strcat(dayString, ".");
  strcat(dayString, (tm.Year+1970));
  Serial.println(dayString);
  showScreen(2,dayString);
}

int printDigits(int digits){
  if(digits < 10)
    return('0');
  return(digits);
}

Ab welcher Stelle oder sollen wir da jetzt suchen?

Gruß Tommy

uint8_t=byte=8Bit ohne Vorzeichen
int8_t=char=8Bit MIT Vorzeichen

So richtig viel muß Da nicht gewandelt werden - einzig dem Compiler muß gesagt werden, ob das höchste Bit nun das Vorzeichen ist, oder eben nicht.

MfG

postmaster-ino:
uint8_t=byte=8Bit ohne Vorzeichen
int8_t=char=8Bit MIT Vorzeichen

... wobei man für die *_t-Typen IIRC <stdint.h> inkludieren muss.

Wieso ist ein „char“ eigentlich vorzeichenbehaftet?

Gruß

Gregor

gregorss:
Wieso ist ein „char“ eigentlich vorzeichenbehaftet?

Das hat mal jemand so festgelegt :wink: weil ASCII nicht mehr braucht.
Als Gegenstück zu byte.

Gruß Tommy

Hi

Meine IDE frisst die *_t-Typen ohne spezielles Include - denke mir also, die IDE macht Da schon was im Verborgenem.

Wieso char mit Vorzeichen ist? kA - ist halt so, wie byte eben kein Vorzeichen hat.
Ggf. konnte man 'so' direkt prüfen, ob ein 'normales' Zeichen (0...127) oder was Spezielles aus irgend einer Code-Page gemeint ist ... ok, aus den Haaren gezogen, aber wäre denkbar :wink:

MfG

Tommy56:
Ab welcher Stelle oder sollen wir da jetzt suchen?

Die Stelle nennt sich treffenderweise "// ab hier ist noch Nachbesserung angesagt". :wink:

Zurück zum Thema:
Ich versuche die Zeit, die per DCF-Library erfolgreich gefunden wurde, aus den variablen tm.Hour usw. in einen String (Char[]) zu packen, damit ich diesen dann in der Displayausgabe der u8g2-Library verwenden kann.

tm.Hour und die anderen Werte sind vom typ uint8_t, soweit es den Compiler an geht und ich es in der Library nachvollziehen konnte. Meine Ausgabefunktion "showScreen()" erwartet char[] weil das auch "u8g2.drawStr()" so möchte, womit ich den Text am ende auf den Display bringe. Soweit ich das richtig verstanden habe.

Das uint8_t die Abkürzung für unsigned int ist habe ich schon bemerkt doch die 8 steht für 8bit oder nicht?
Problem ist also welche 8bit der 16bit eines unsigned int sind es, die oberen oder unteren?
Genügt schiften oder muss ich doch etwas anderes versuchen?

Wie übergibt man uint8_t in ein char[]?
Mit "(char)tm.Hour" hat es schon mal nicht funktioniert.
Auch "(byte)tm.Hour" hilft nichts.
Da fehlt mir wohl irgend welches Grundlagenwissen. :frowning:

-------Nachtag-------
Jetzt hab ich etwas zum laufen bekommen.
Leider werden jetzt nur noch 5 Zeichen pro Zeile angezeigt (auf dem Display).
Für heute ist es genug, ich geh ins Bett.

#include <U8g2lib.h>     // https://github.com/olikraus/u8g2
#include <Wire.h>        // für i2c (Display/RTC)
#include <DCF77.h>       // https://www.arduinolibraries.info/libraries/dcf77
#include <TimeLib.h>     // https://github.com/PaulStoffregen/Time

U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, SCL, SDA, U8X8_PIN_NONE);
// 5x "u8g2_font_pixelle_micro_tr"
// 7x "u8g2_font_profont11_tr"
// 7x "u8g2_font_finderskeepers_tr"
// 10x "u8g2_font_crox2tb_tr"
// 12x "u8g2_font_helvB12_tr"

#define DCF_PIN 3         // muss interrupt fähig sein
time_t time;
time_t DCFtime = 0;
DCF77 DCF = DCF77(DCF_PIN,digitalPinToInterrupt(DCF_PIN));
bool dcfSyncNowMSG = true;
bool dcfSyncOK = false;

void setup() {
 Serial.begin(9600);
 u8g2.begin();
 u8g2.setFont(u8g2_font_finderskeepers_tr);
 showScreen(1,"Willkommen");
 u8g2.sendBuffer();
 DCF.Start();
 delay(1000);
}

void loop() {
  if (!dcfSyncOK){
	  if (DCFtime!=0) {
      u8g2.clearBuffer();
      showScreen(1,"DCF Sync. OK");
	  	digitalClockDisplay(DCFtime);
      dcfSyncOK = true;
	  }
    else{
      DCFtime = DCF.getTime();
      if (dcfSyncNowMSG){
        u8g2.clearBuffer();
        showScreen(1,"DCF Sync. ...");
        dcfSyncNowMSG = false;
      }
    }
    delay(1000);
  }
}

void showScreen(int line, char msg[]) {
  if (line == 1){
    u8g2.drawStr(0,8,msg); // (1-128,1-32,"")
  }
  if (line == 2){
    u8g2.drawStr(0,16,msg);
  }
  if (line == 3){
    u8g2.drawStr(0,24,msg);
  }
  if (line == 4){
    u8g2.drawStr(0,32,msg);
  }
  u8g2.sendBuffer();
}

void digitalClockDisplay(time_t _time){
  tmElements_t tm;   
  breakTime(_time, tm);
  u8g2.clearBuffer();
  String tString = "Uhrzeit: " + String(tm.Hour, DEC) + ":" + String(printDigits(tm.Minute), DEC) + ":" + String(printDigits(tm.Second), DEC);
  char outData[sizeof(tString)];
  tString.toCharArray(outData, sizeof(tString));
  Serial.println(outData);
  showScreen(1,outData);
  tString = "Datum: " + String(tm.Day, DEC) + "." + String(tm.Month, DEC) + "." + String((tm.Year+1970), DEC);
  outData[sizeof(tString)];
  tString.toCharArray(outData, sizeof(tString));
  Serial.println(outData);
  showScreen(2,outData);
}

int printDigits(int digits){
  if(digits < 10)
    if (digits == 0){
      return(0,0);
    }
    else{
      return(0);
    }
  return(digits);
}

Also der Umweg über String ist ja nun wirklich nicht schön.

Schau Dir mal sprintf/snprintf an oder schreibe es direkt in das Char-Array. Dazu gibt es hier ein paar Hilfen.

Gruß Tommy

genau das habe ich mittlerweile getan. :slight_smile:
sprintf/snprintf hab ich heute morgen auf der suche nach dem Display anzeige Problem gefunden.

Im letzten Code hatte ich ja String verwendet um alles anzufügen und dann in Char[] zu übergeben.
Dabei musste ich feststellen das sizeof bei einem String nicht funktioniert sondern .length nötig ist.
Aber letzten Endes hab ich sprintf ausprobiert und was soll ich sagen, typischer fall von "kaum macht man es richtig, schon geht's".

  char outData[10];
  sprintf(outData,"%02d:%02d:%02d", tm.Hour, tm.Minute, tm.Second);
  u8g2.drawStr(0,10,outData);

Und weil ich mir sooo gerne die Zähne an Problemen ausbeiße hänge ich schon am nächsten.
Die RTC Librarys für den DS3231 aber auch die kompatible für den DS1307 blockieren mir alle die Displayausgaben der U8g2lib. Vermutlich wegen deren "wire.Begin();".
Ich werde mich jetzt nochmal genauer mit der DS3231M Library beschäftigen um raus zu finden wo mein Denkfehler oder die Inkompatibilität ist.

Schau mal hier den Beitrag #105 von Oli Kraus an. Evtl. verkürzt der die Suche.

Gruß Tommy

Du sprichst vom Hinweis auf den i2c Bustackt,
der mit "u8g2.setBusClock(100000);" evtl. händisch eingestellt werden sollte?
Laut Wiki der Library muss der Befehl vor dem ersten aufrufen (also begin oder init) stehen.
Mein Display hat im Datenblatt keine Angabe und der RTC kann i2c mit 400kHz.
Darum hab ich nun den Tackt von 100kHz bis 400kHz ausprobiert aber das hat nichts geändert.

Trotzdem Danke für den Hinweis, danach hätte ich bestimmt ewig gesucht.
Ich versuche nun mal die u8g2 gegen die u8g zu ersetzen und hoffe ich darf nicht zu viel anpassen.

Für die DS3231 brauchst Du doch keine Lib, die kannst Du direkt über Wire programmieren.

Gruß Tommy