Binäre DCF77 Uhr mit exponentiellem Filter und Blinkenlighty

Ich glaube ich werde das nie lernen mit den Variablen Typen.
Ich versuche gerade das Funkuhrsignal in eine RTC zu schreiben.
von der Funkuhr bzw der Time.h bekomme ich ja :

sekund() minute() hour() year() month() day()

Das sind int wenn ich mich nicht irre. Diese werden mir auch schön im seriellen Monitor angezeigt:

17.12.2012 16:31:02

So die RTC (ich habe hier eine softI2C) nimmt die Daten richtig an wenn ich sie so schreibe:

uint8_t d[4];
d[3]=0x12; // Jahr
d[2]=0x12; // Monat
d[1]=0x16; // Tag
d[0]=0x01; // Wochentag

Das ist HEX-Schreibweise wenn ich mich nicht irre.
Wenn ich jetzt einfach die ints versuche zu übergeben sieht meine ausgelesene RTC so aus;

RTC: 11.0C.2001 01:1F:01

Das ist irgendwie falsch!
Gehe ich recht in der Annahme das ich aus dem int ein HEX machen muss?
Und wenn ja, wie?

MueThoS:
Gehe ich recht in der Annahme das ich aus dem int ein HEX machen muss?
Und wenn ja, wie?

Nein, Du mußt nur Deine RTC-Library korrekt anwenden!

Dazu schaust Du nach, welche RTC-Library Du installiert hast (da gibt es wohl viel mehr als nur eine).
Dann lädst Du Dir das Beispielprogramm zu dieser RTC-Library in Deine Arduino-Software.
Dann studierst Du das Beispielprogramm.

Beispielprogramme sind kommentiert und in den Programmkommentaren stehen die notwendigen Hinweise, wie die Library angewendet wird.

Mit 0x beginnende Zahlen sind unter C die Hex-Schreibweise im 16er System
0x12 = 116 + 2 = 18
0x16 = 1
16 + 6 = 22
0x01 = 0*16 + 1 = 1

Dies versuche ich ja!

Ich habe, wie gesagt, die softi2c nennt sich i2cMaster.
Das Beispiel Programm habe ich offen.

Und dort ist folgendes interessant:
wenn ich die Zeit stellen will wird dies aufgerufen:

uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t &n) {
  uint16_t v;
  if (!hexRead(v)) return false;
  uint8_t d = 10 * (v >> 4) + (v & 0XF);
  if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) {
    PgmPrintln("Invalid");
    return false;
  }
  n = v;
  return true;
}

Was ich hier noch verstehe ist das hexRead aufgerufen wird.
dann kommt etwas was ich nicht verstehe. (uint8_t d = 10 * (v >> 4) + (v & 0XF):wink:
Und dann wird geschaut ob die Werte gültig sind.

hexRead:

uint8_t hexRead(uint16_t &v) {
  uint16_t n = 0;
  while (!Serial.available());
  while (Serial.available()) {
    uint8_t c = Serial.read();
    n <<= 4;
    if ('a' <= c && c <= 'f') {
      n += c - ('a' - 10);
    }
    else if ('A' <= c && c <= 'F') {
      n += c - ('A' - 10);
    }
    else if ('0' <= c && c <= '9') {
      n +=  c - '0';
    }
    else {
      PgmPrintln("Invalid entry");
      return false;
    }
    delay(10);
  }
  v = n;
  return true;
}

es wird gewartet bis was über Seriell rein kommt.
Dann werden die kommenden Daten in c gelesen
dann wird geschaut ob die Werte Zahlen sind (so denke ich)
und der rest ist wieder Bahnhof.

Hier wird die RTC beschrieben:

uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count) {
  // issue a start condition, send device address and write direction bit
  if (!rtc.start(DS1307ADDR | I2C_WRITE)) return false;

  // send the DS1307 address
  if (!rtc.write(address)) return false;

  // send data to the DS1307
  for (uint8_t i = 0; i < count; i++) {
    if (!rtc.write(buf[i])) return false;
  }

  // issue a stop condition
  rtc.stop();
  return true;
}

Und wenn ich mir das anschaue würde ich sagen uint8_t *buf sollte mein Wert sein.
Also ein INT würde ich vermuten. Aber meine sekund() usw sind doch INTs

Und weil ich das nicht verstehe komme ich nicht weiter.

MueThoS:
Und weil ich das nicht verstehe komme ich nicht weiter.

Ich glaube, Du verhedderst Dich da in den Untiefen von Umrechnungen mit Zahlensystemen, von denen Du weder etwas verstehst noch dass Du sie benötigst.

BCD Zahlen sind Binary Coded Dezimals, binärcodierte Dezimalzahlen:

Damit kann man jede dezimale Ziffer von 0 bis 9 mit vier Bits darstellen.

Das wirst Du mit Sicherheit alles gar nicht benötigen.

Was Du immer benötigst, wenn es um Zeiten geht, das ist die Unix-Zeit.

Das ist ein long integer (32-Bit) Ganzzahlenwert mit der Anzahl der Sekunden seit dem 01.01.1970.

DAS ist es, womit Programmierer ihre Uhrzeiten handeln. Und wenn Du irgendeine Zeit-Library hast, dann gibt es einerseits bequeme Funktionen, um Tag, Monat, Jahr, Stunde, Minute, Sekunde in Unixzeit umzurechnen. Und umgekehrt genauso.

Und für Deine RTC-Library gibt es mit ziemlicher Sicherheit sowohl eine Schreibfunktion, der Du die Unixzeit übergeben kannst und auch eine Lesefunktion, von der Du die Unixzeit aus der Uhr geliefert bekommst.

Du hast es also im Endeffekt nur mit vier Funktionen zu tun, und die fressen allesamt Dezimalzahlen:

  1. Eine Umrechenfunktion von Tag, Monat, Jahr, Stunde, Minute, Sekunde in Unixzeit
  2. Eine Umrechenfunktion von Unixzeit in Tag, Monat, Jahr, Stunde, Minute, Sekunde
  3. Eine Uhr-Stellen Funktion, die eine Unixzeit zum Stellen der RTC übergeben bekommt
  4. Eine Uhr-Abfragen Funktion, die eine Unixzeit von der RTC geliefert bekommt

Wenn Du diese vier Funktionen bei Dir nicht findest, schreib mal genau, welche Time- und Realtime-Libraries Du installiert hast, dann schau ich mal in die Library rein!

Und Zahlensysteme wie Binärsystem, Hexadezimalsystem, und BCD-Zahlen kannst Du sicher getrost auf Lücke setzen, wenn Du nur eine Uhr stellen oder abfragen oder mit Zeiten rechnen möchtest, das sollte alles mit Dezimalzahlen zu erschlagen sein.

Unter "i2cmaster" finde ich nur eine Library, die was mit LCD-Displays zu tun hat, nicht mit RTC Uhren.

Also,
ich habe folgende Libraries die ich nutze:
softi2c von folgender Seite: (erster Beitrag)
http://forums.adafruit.com/viewtopic.php?f=25&t=13722
die Heißt dann I2cMaster

Time.h (Standard)

Hier aus diesem Fred:
DCF77.h
MsTimer2.h

Ich habe auch schon versucht die Libraries zu analysieren aber ich komme eben nicht weiter, deshalb frag ich.

MueThoS:
Also,
ich habe folgende Libraries die ich nutze:
softi2c von folgender Seite: (erster Beitrag)
http://forums.adafruit.com/viewtopic.php?f=25&t=13722
die Heißt dann I2cMaster

Time.h (Standard)

Hier aus diesem Fred:
DCF77.h
MsTimer2.h

Ich habe auch schon versucht die Libraries zu analysieren aber ich komme eben nicht weiter, deshalb frag ich.

Das ist jetzt aber nicht Dein Ernst, oder?

Du hast keine RTC-Library für Deine RTC in Verwendung?
Warum denn das nicht?

Als normaler Arduino-Anfänger macht man es so:

  1. Man schaut nach, was für ein Uhrenbaustein auf der RTC verbaut ist, z.B. ein Dallas 1307
  2. Dann sucht man eine Arduino-Library zur Ansteuerung, z.B. für einen Dallas 1307
  3. Dann verwendet man die Funktionen der Library zum Auslesen und Einstellen der Uhr

Was Du da vorhast, die Bit-Schubsereien über den I2C-Bus selbst zu codieren, ist absolut NICHT anfängergeeignet.

Anfängergeeignet zum Stellen und Auslesen einer RTC mit dem gängigen Dallas 1307 Chip wäre beispielsweise so eine Library:

Vielleicht passt's ja und Du hast eine RTC mit 1307, dann schau da mal rein!

Vielleicht drücke ich mich nur nicht richtig aus.

Die RTClib, die Du verlinkt hast, habe ich. Würde auch funktionieren. Möchte ich für meinen Anwendungsfall aber nicht nutzen.
Es sei denn ich kann sie auf andere PINs legen.

Die Lib die ich hier nutze (I2cMaster) Funktioniert mit dem Beispiel auch.
In meiner Umsetzung funktioniert es auch wenn ich die Daten mal zum Testen hard code:

...
d[1]=0x17;
...
writeDS1307(3, d, 4)

Für Heute den 17ten.

Nur leider ist zwischen day() der Time-Lib und 0x17 ein unterschied.

Das ist BCD :wink:
Binär Codierte Dezimal - Zahlen: 4 Bit Einerstelle, 2 bis 4 Bit Zehnerstelle.

pups-einfach: Schau auf Seite 5 dieses Datenblatts, http://www.sparkfun.com/datasheets/Components/DS1307.pdf
Da ist jedes Bit der 7 Datenbytes einer 1307 beschrieben.
(jedenfalls einfacher als auf einem Arduino mit Unix-Zeit rumzumachen)

Nur leider ist zwischen day() der Time-Lib und 0x17 ein unterschied.

byte day() {
byte ram = readDS1307Byte(3); // offset des DS1307 Bytes mit dem Kalendertag.
return (ram>>4)*10 + ram&0x0f;
}

Dafür brauchst du wirklich keine Library :wink:

Es sei denn ich kann sie auf andere PINs legen.

I2C sollte man nicht auf andere Pins legen...

MueThoS:
Möchte ich für meinen Anwendungsfall aber nicht nutzen.

Wenn Du es auf die harte Tour tun willst, wirst Du nicht umhin kommen, Dich in das ganze Klein-Klein der Bit-Schubsereien gründlich einzuarbeiten.

MueThoS:
d[1]=0x17;
...
Für Heute den 17ten.

0x17 ist ja auch nicht 17, sondern 0x17 ist 1*16+7=23.
:wink:

jurs:
0x17 ist ja auch nicht 17, sondern 0x17 ist 1*16+7=23.
:wink:

Manchmal eben doch.
BCD ist einfach, das konnten MicroController schon, als sie noch nicht Mikro waren und noch aus Relais gebaut wurden :wink:

OK, dann haken wir das Thema jetzt hier ab und ich frage was ganz anderes:

Ich möchte sozusagen ein Shield basteln welches nur eine Aufgabe hat:
DCF77 auswerten und in eine RTC schreiben.

Es soll dann möglich sein mit dem Arduino von dem Shield folgende Informationen zu bekommen:

  1. Uhrzeit (aus der RTC)
  2. Wann wurde zuletzt gesynct
  3. Haben wir noch eine richtige Zeit
  4. Es soll möglich sein den SQW/Out zu konfigurieren dieser soll an einen Pin anliegen
    Solche Sachen halt. Einfach die Auswertung und Vorhaltung der aktuellen Zeit outsourcen.

Und da die Kommunikation zwischen RTC und uC unabhängig laufen sollte wollte ich diesen I2C-Bus auf anderen Pins haben.
Und die Hardware I2C soll dann später mit dem Arduino kommunizieren.

Die Frage ist wenn ich die Hardware-I2C nutze kann ich da nicht wild umher funken oder?

Die Frage ist wenn ich die Hardware-I2C nutze kann ich da nicht wild umher funken oder?

Wenn nur ein Master da ist, kann der "wild umher funken".
"DCF77 Auswertung in eine RTC schreiben" sollte dann der gleiche Arduino (?) machen, der auch den Rest macht.

Die gefilterte Zeit der DCF kommt doch immer noch mit nur ca. 1 bit / sek, oder hab ich da was nicht mitgekriegt ?

Das Shield kümmert sich um alles was mit Zeit zu tun hat, so mein Plan!
Ursprünglich hatte ich gehofft das man auf dem Shield nicht umbedingt einen 328 braucht sondern was kleineres.

mom ich versuch das mal zu krickeln....

Ein Kunstwerk, oder?

So, und jeder der Eine Uhr bauen will steckt dieses Modul auf und hat über I2C immer die aktuelle Uhrzeit.

Auf dem Shield könnte evtl. softi2csinnvoll sein...

Soll das Shield sich zum Arduino genau wie eine DS1307 - RTC verhalten, damit alle Libraries gehen ?

"Wild umherfunken" ist natürlich nicht, da hast du Recht :wink:

Hatte ich jetzt noch nicht drüber nach gedacht aber Du hast recht!
Wir halten fest das Shield soll sich so verhalten wie die DS1307 RTC.
Ich glaube ich mach doch mal einen eigene Fred auf für das Dingen.

Zu meinem Thema geht es hier weiter.

Dann mülle ich den Wissenschaftlichen Teil hier nicht weiter voll. Den hab ich sowieso nicht verstanden :~

Ausbaustufe 1 meines DCF77 Projekts ist hier:

Die alte Version mit dem exponentiellen Filter ist nur noch ein Benchmark :wink: Der neue Filter wird Welten besser. Und natürlich werde ich auch noch eine fette Fehlerkorrektur hinterherschalten. Es kommen noch ein paar Ausbaustufen zu diesem Projekt.

Die Feldstärke in DB zu ermitteln ist mit den einfachen Modulen nicht möglich. Die finale Ausbaustufe meiner Uhr wird aber die Qualität des dekodierten Signals ermitteln. Aktueller Stand ist, daß ich jetzt auch die Sekunden dekodieren kann. Ich bin exakt im Plan :wink:

Die nächste Ausbaustufe ist fertig und dokumentiert: What time is it? | Blinkenlight. Decoding Time Data | Blinkenlight. Die aktuell in Entwicklung befindliche Ausbaustufe hat auch die Sommerzeitumstellung richtig hinbekommen, ist aber noch nicht fertig dokumentiert :slight_smile:

Bekommst Du am Ende eigentlich mit Deinem DCF-Sketch den Speicher eines UNO voll, oder bleibt noch ein Rest an Speicher für was anderes übrig? :wink:

Irgendwie verstehe ich das mit dem Hamming-Code nicht ganz. Einerseits wird das DCF-Signal nur mit einem einfachen Parity-Code gesendet, und Du konstruierst aus erwarteten Daten (bei bereits korrekt laufender Uhr?) und eintreffenden Daten ein Scoring, mit dem Du auch bei ständig falschen Parity-Codes aus der Abfolge mehrer Minuten nacheinander trotzdem die richtigen Werte auslesen willst?

Irgendwie wird mir das alles zu hoch, was Du da machst. :fearful:

[Edit] Jetzt habe ich mir mal den Sketch heruntergeladen und getestet: Huch, der ist ja gar nicht so groß?!
Und die exponentielle Filterung mit Sampling des Eingangssignals ist auch gar nicht mehr drin?!

Und wie lange braucht der Sketch, um die Uhrzeit zu bekommen? Habe hier mal gerade mit meinem Pollin-Modul und leichten Störungen getestet. Die "Quality"-Zeilen (die mir nichts sagen), habe ich mal dazwischen entfernt.

Dein Sketch fängt an mit:
Decoded time: ??:??:00
Wechselt nach einer Weile auf die richtige Sekunde:
Decoded time: ??:??:20
Decoded time: ??:??:21
Decoded time: ??:??:22
Decoded time: ??:??:23
...

Irgendwann wird wohl Stunde und Minute zu 00 und 00 erkannt (was nicht korrekt ist, Sekunde stimmt):
Decoded time: 00:00:26
Decoded time: 00:00:27
Decoded time: 00:00:28
Decoded time: 00:00:29
Decoded time: 00:00:30
Decoded time: 00:00:31

Dann wird die Stunde wieder unbekannt, die Minute zählt hoch (immer noch falsch), die Sekunde stimmt weiterhin:
Decoded time: ??:01:00
Decoded time: ??:01:01
Decoded time: ??:01:02
Decoded time: ??:01:03
Decoded time: ??:01:04
Decoded time: ??:01:05
Decoded time: ??:01:06
Decoded time: ??:01:07

Dann wird die Stunde wieder (falsch) zu 00 erkannt, die Minute unbekannt, die Sekunde stimmt weiterhin:
Decoded time: 00:??:20
Decoded time: 00:??:21
Decoded time: 00:??:22
Decoded time: 00:??:23
Decoded time: 00:??:24
Decoded time: 00:??:25
Decoded time: 00:??:26

Dann kommt wieder die Minute (Stunde falsch, Minute geht um wenige Minuten falsch):
Decoded time: 00:22:05
Decoded time: 00:22:06
Decoded time: 00:22:07
Decoded time: 00:22:08
Decoded time: 00:22:09
Decoded time: 00:22:10
Decoded time: 00:22:11
Decoded time: 00:22:12

Dann merkt er wieder, dass mit der Minute was nicht stimmt:
Decoded time: 00:??:14
Decoded time: 00:??:15
Decoded time: 00:??:16
Decoded time: 00:??:17
Decoded time: 00:??:18
Decoded time: 00:??:19

Nach ca. 15 Minuten stimmen dann Minuten und Sekunden:
Decoded time: 00:31:01
Decoded time: 00:31:02
Decoded time: 00:31:03
Decoded time: 00:31:04
Decoded time: 00:31:05

Na ja.

Naja, am Ende wird die Uhr wohl so 22kBytes verpulvern. Das ist ziemlich wenig im Vergleich zur Leistungsfähigkeit. Einfache DCF77 Uhren (insbesondere alle kommerziellen) Uhren werden ja nicht einmal mit 1 Bitfehler pro Minute fertig. Meine Uhr wird locker mit mehr als 15 Bitfehler pro Minute fertig.

Das mit dem Hamming Code ist so, daß es keinen "Hamming Code" gibt. Es gibt eine "Hamming Metrik". Im Prinzip ist es ganz einfach. Stell Dir vor jede Minute würde das gleiche Signal gesendet. Dann wäre der Durchschnitt der empfangenen Werte eine naheliegende Schätzung für die richtige Zeit. Jetzt ändert sich die Zeit aber jede Minute. Was aber gleich bleibt ist der Zeitverlauf. Ich muß also nur die Phase erkennen. D.h. für verschiedene Startzeiten ergeben sich verschiedene aber jeweils vorbestimmte Zeitverläufe. Ich muß also nur den "naheliegendsten" Zeitverlauf bestimmen. "Naheliegend" zum empfangenen Signal eben. Die Frage ist wie man "Nähe" bei Signalen misst --> da kommt die Hamming Metrik ins Spiel. Das ist alles.

Probleme Dir dabei macht vermutlich, daß Dir nie jemand verraten/gezeigt hat, daß man "Abstand" auch anders festlegen kann als "euklidischer Abstand im 3-dimensionalen Raum".

Und ich will das nicht nur können, meine Uhr funktioniert bereits bestens. Wie gesagt, 15 Bitfehler pro Minute (und zwar JEDE Minute) sind kein besonders großes Problem. Bei 10 Bitfehlern pro Minute braucht die Uhr weniger als 15 Minuten um die korrekte Zeit zu ermitteln UND danach dauerhaft auf die Sekunde verriegelt zu bleiben.