www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik DCF 77 Impulse


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,
ich wollte Fragen, wie es genau mit den Impulsen vom DCF 77 Empfänger 
aussieht.


Wenn das Signal 100 ms lang ist, ist es eine logische 0.
Anschliessend folgt eine Pause von 900 ms.

Wenn das Signal 200 ms lang ist, ist es eine logische 1.
Anschliessend folgt eine Pause von 800 ms.

Wenn die 58 Sekunde gesendet wurde, folgt eine Pause von 1800 ms bzw. 
1900 ms.



Anhand dieses Pausensignals, lässt sich die Funkuhr synchronisieren.

Nun meine Frage:
Liegt bei einem Signal von 100 oder 200 ms eine Spannung am Ausgang des 
DCF77 an und liegt bei einer Pause von 800,900,1800, 1900 ms keine 
Spannung an.


Wäre für jede Hilfe dankbar, denn dann könnte ich endlich das Programm 
für den DCF77 Empfänger schreiben.

Autor: balu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Liegt bei einem Signal von 100 oder 200 ms eine Spannung am Ausgang des
DCF77 an und liegt bei einer Pause von 800,900,1800, 1900 ms keine
Spannung an.

Antwort: kommt auf den Empfänger an! den den ich habe der kann beides.

Autor: Koko Lores (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt verschiedene Module, das Signal ist ggf. invertiert. Aber Deine 
Annahme ist richtig. guck mal: DCF77

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also stimmt meine Annahme....
Was bedeutet aber: invertiert

Normalerweise wird bei 100 oder 200 ms eine Spannung angelegt
Bei der Pause, liegt dann keine Spannung an.

Bedeutet invertiert: Das es dann umgedreht ist?

Autor: Martin Kreiner (maart)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> Also stimmt meine Annahme....
> Was bedeutet aber: invertiert
>
> Normalerweise wird bei 100 oder 200 ms eine Spannung angelegt
> Bei der Pause, liegt dann keine Spannung an.
>
> Bedeutet invertiert: Das es dann umgedreht ist?

Riiiichtig!

Autor: Joachim Börke (joachimb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Zeitverhalten hast Du in der ersten Nachricht genau beschrieben. Da 
das Zeitsignal, abhängig vom Empfänger, als "1" oder als "0" ausgegeben 
wird, bietet es sich an, das Empfangsprogramm unabhängig von der 
Signalpolarität zu schreiben.
Damit kann dann das DCF-Signal von jedem Empfänger dekodiert werden.

Gruß
Joachim

Autor: Hendi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
<klugschiss>
An DCF77 liegt immer Spannung an, aber innerhalb der Sekunde entweder 
800 ms oder 900 ms ne höhere als in den verbleibenden 100 ms bzw. 200 ms 
:)
</klugschiss>

Hendi

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist gut,
denn mit diesen Informationen kann ich nun ohne weiteres in einen Atmel 
programmieren.

Das bedeutet, das ich ein Datensignal und Pausensignal "nicht 
invertiert, oder invertiert" von einem Dateneingang lesen kann.

Liegt dort eine Spannung an:
Variable 1 solange addieren, bis die Spannung abfällt.


Fällt die Spannung ab:
Variable 2 solange addieren, bis die Spannung wieder anliegt.

Liegt die Spannung wieder an, werden die Werte von Variable 1 u. 
Variable 2
ausgewertet und in die entsprechenden Variablen abgelegt.

Auswerten bedeutet:
Anhand des Wertes von Variable 1 u. Variable 2, lässt sich ermitteln, ob 
eine logische 1 oder 0 gesendet wurde.

Hierzu wird auch pro so einem Durchlauf in die Variable 3 immer der Wert 
1 hinzuaddiert.

Das ist nötig, denn nur so weiss man, bei was für einen Sekundensignal 
man sich gerade befindet und wie man den zusätzlich gesendeten 
Digitalcode "0 oder 1" zu speichern hat.


Anschliessend werden die Variable 1 u. Variable 2 wieder auf den Wert 0 
gesetzt, so dass man dort wieder neue Wert addieren kann.


Darauffolgend beginnt wieder alles von vorne......

Wird das 58 Sekundensignal mit einer Pause von 1800 ms bzw. 1900 ms 
gesendet, dann werden entsprechende Variablen wieder gelöscht.


Die entsprechend ausgewerteten Daten, wie Datum u. Uhrzeit wird dann 
über 7 Segmentanzeigen ausgegeben.







Autor: Obelix (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einige DCF-Empfäger haben aber auch einen Open Kolektor Ausgang. Dann 
kommt da keine Spannung raus.

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann braucht man eine Pullup nach Vcc. Diesen kann man im Layout 
sicherheitshalber vorsehen. Der interne im Atmel ist für diesen Zweck zu 
hchohmig, da kann es zu Störungen kommen. Im Übrigen sind die DCF-Pulse 
nicht supergenau, sondern schwanken -je nach Empfänger- so um +-20% um 
den Idealwert. Im Programm müssen also Fenster für die jeweiligen "1" 
und "0" Pulse vorgesehen werden, die diese Toleranzen berücksichtigen 
und "Ausreißer" ausmaskieren.

Autor: Power (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einfach die Bits addieren geht leider auch nicht, ich benutze dafür eine 
Look-up Tabelle, in der stehen die Wertigkeiten der einzelnen Bits 
(Quasi-BCD). Auch die Prüfbits (Paritätsbits) sollten ausgewertet werden 
um den Empfang sicherer zu machen.

Autor: Stromspannung (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Einige DCF-Empfäger haben aber auch einen Open Kolektor Ausgang. Dann
>kommt da keine Spannung raus.

Spannung kann nirgends rauskommen. Die kann nur anliegen bzw. sie kann 
dafür sorgen, dass Strom fliesst (irgendwo heruaskommt...).

Autor: Günter R. (galileo14)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du arbeitest besser mit Signalwechseln, nicht mit Logikpegeln, wie es 
Joachim Börke schon ganz richtig angedeutet hat; erzeuge doch mit jedem 
Signalwechsel einen Interrupt (geht bei den AVR's ganz leicht) und lese 
dort einen Timer aus; die "0" und "1" ergibt sich dann durch die 
aufgelaufenen Zeiten; dazu kann man Konsistenztests machen (nach einer 
100ms-Zeit muß eine 900ms-Zeit kommen, nach einer 200ms-Zeit muß eine 
800ms-Zeit kommen, oder es kommt die 1800ms- oder die 1900ms-Zeit); und 
die Zeitfenster beachten (Toleranzen, wurde auch schon angesprochen).

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der Codesammlung gibts auch sehr effizienten Beispielcode:

Beitrag "DCF77 Uhr in C mit ATtiny26"


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das mit dem Auslösen eines Interrupts bewerkstellige ich dann 
folgendermasen:

Liegt eine Spannung an, dann wird eine Funktion ausgeführt.
Diese Funktion addiert pro Schleifendurchlauf einen Wert bei einer 
Variable hinzu.

Fällt nun diese Spannung ab, dann hört diese Funktion auf zu arbeiten.
Das bedeutet, dass dann diese Variable einen Wert hat und dieser Wert 
der
Variable sagt dann einem, wie lange das Signal war.

Bei 100 ms = ....
Bei 200 ms = ....

Da nun die Spannung abgefallen ist, wird eine andere Funktion 
aufgerufen.
Diese Funktion addiert nun pro Schleifendurchlauf einen Wert bei einer 
Variable hinzu.

Hiermit weiss man dann, ob das Pausensignal 800,900,1800 oder 1900 ms 
lang war.


Wenn nun wieder eine Spannung anliegt, hört das Zählen dieser Variable 
auf.

Nun werden diese Werte ausgewertet u. dann die Variablen von der 
Funktion 1 und Funktion 2 auf den Wert 0 gesetzt.

Anschliessend beginnt wieder alles von vorne.

Wie weiss ich aber, was für Wertigkeiten diese Variablen haben, 
schliesslich werden ja diese Werte intern im Mikrocontroller 
gespeichert.

Ich dachte, dass ich die Werte der Variablen über Schieberegister über 
Leds ausgebe u. dann mit einer Webcam aufzeichne.

Nun kann man die Bilder der Webcam auswerten u. anschliessend das 
Programm im Atmel dementsprechend umändern.


Wüsstet ihr eine andere Möglichkeit, dann lasst es mich bitte wissen.






Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine Beschreibungen lesen sich so, als ob du noch ein
paar Vorübungen brauchen würdest, bevor es Sinn macht sich an
einer DCF-77 zu versuchen.

Du fängst mal damit an, dir eine Zeitbasis zu schaffen.
Dazu nimmst du einen Timer und stellst den so ein, dass
du alle paar ms einen Interrupt kriegst.

In der Interruptfunktion (von der du nun weist, in welchem
Zeitraster sie aufgerufen wird) überprüfst du den jetzigen
Zustand des Eingangspins an dem der Empfänger hängt und
vergleichst ihn mit dem Zustand, den er beim letzten
Aufruf der Interrupt Funktion hatte:
* Sind die beiden gleichen, dann hat sich am Signal nichts
  getan und du zählst einfach nur eine Variable um 1 höher
  (die kommt später noch ins Spiel und misst einfach nur,
  wie lange das Signal war).
* Sind die beiden aber ungleich, dann hast du eine Flanke
  gefunden. Die kann von 0 nach 1 oder von 1 nach 0 sein.
  Das interessiert aber nicht weiter, denn jetzt kommt
  obige Variable ins Spiel.
  Diese Variable ist ja ein Mass für die Zeit, die von einem
  Flankenwechsel zum nächsten Flankenwechsel vergangen ist
  (dazu wird sie am Ende dieser Behandlung auf 0 gesetzt, um
  dann wieder langsam hochgezählt zu werden).
  Entscheidend ist: Diese Zeitdauer kann nicht beliebig sein.
  Sie kann nur sein:
    * 100 ms
    * 200 ms
    * 800 ms
    * 900 ms
    * 1800 ms
    * 1900 ms
  (mit entsprechenden kleinen Variationen versteht sich).

  Die Fälle 800ms und 900ms interessieren nicht weiter.
  Interessanter sind die Fälle 100 bzw. 200 ms. Je nachdem
  was vorliegt, hast du entweder eine 0 oder eine 1 empfangen.

  Die Fälle 1800 ms bzw. 1900 ms sind nur deswegen interessant,
  weil sie signalisieren, dass jetzt ein neues Pulstelegramm
  anfängt. Irgendwo werden ja die 0 und 1 von den 100 bzw. 200ms
  gespeichert. Das wird fürs erste wahrscheinlich ein Array sein.
  Und ein Auftreten von 1800 bzw. 1900 ms bedeutet lediglich,
  das der Schreibindex in das Array wieder auf 0 gesetzt werden
  soll.

  Zusammengefasst:
  Zeitdauer < 150 ms ?         Eine 0 speichern
  else Zeitdauer < 250 ms ?    Eine 1 speichern
  else Zeitdauer > 1500 ms ?   Neues Telegramm beginnt


In Pseudo-Code

uint8_t EingangVorher;
uint8_t Telegramm[60];
utin8_t NextIndex;

ISR( ... )
{
  uint8_t EingangJetzt;

  EingangJetzt = PIN ....

  if( EingangJetzt == EingangVorher )
    PulsZeit++;

  else {
    EingangVorher = EingangJetzt;

    if( PulsZeit < 150 )          // 100 ms
      Telegramm[NextIndex++] = 0;

    else if( PulsZeit < 250 )     // 200 ms
      Telegramm[NextIndex++] = 1;

    else if( PulsZeit > 1500 ) {
      NextIndex = 0;

      // Werte das Telegramm aus
    }

    PulsZeit = 0;
  }
}

Für eine erste Version sollte das so in etwa reichen.

Fang erst mal damit an, dir einen Timer aufzusetzen um
damit die Zeitbasis für den Interrupt hinzukriegen.
Also erste Übung könntest du ja mal mit dem Timer eine
blinkende LED machen.

Ach ja: In deinem Programm werden da natürlich nicht die
Zahlenwerte 150, 250 und 1500 auftauchen. Die korrekten
Werte hängen davon ab, wie du den Timer konfigurierst und
in welchen Zeitabständen ein Interrupt generiert wird.

Autor: Joachim Börke (joachimb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Strategie macht ein gutes Programm aus.

Im ersten Schritt haben wir festgestellt, dass es besser ist, Pulslängen 
zu bestimmen und daraus die Datenbits zu ermitteln, als auf eine "1" 
oder eine "0" zu warten und darüber zu grübeln ob der Empfänger die 
richtige Signalpolarität hat.

Die Idee, solange zu zählen, wie Spannung anliegt, ist sicher zum 
funktionieren zu bringen. Es ist wesentlich besser, statt dessen mit 
einem Timer des Controllers definierte Zeitimpulse zu erzeugen und diese 
zu zählen. (Wenn man mit der Armbanduhr in der Hand eine Zeit mißt, 
macht man das ähnlich)

Die Idee, mit dem (unbekannten) DCF-Signal Interupts auszulösen, führt 
dann zu Problemen, wenn Störimpulse vorhanden sind. Das ist dann 
aufwendig zu umschiffen.

Es ist sicher eine gute Idee, den von Karl Heinz vorgeschlagenen Weg zu 
verfolgen und zum funktionieren zu bringen.

Viel Erfolg
Joachim

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zitat:

Die Idee, solange zu zählen, wie Spannung anliegt, ist sicher zum
funktionieren zu bringen. Es ist wesentlich besser, statt dessen mit
einem Timer des Controllers definierte Zeitimpulse zu erzeugen und diese
zu zählen. (Wenn man mit der Armbanduhr in der Hand eine Zeit mißt,
macht man das ähnlich)


Diese Idee habe ich jetzt wiegesagt auch in Basic umgesetzt.
Wenn die entsprechenden Bauteile für die Schaltung bei mir sind und ich 
alles miteinander verschaltet habe und ich den entsprechenden 
Programmiercode in das Flash-Rom des Atmel übertragen habe, werde ich 
bei erfolgreichem Lauf der Funkuhr den Basic-Programmiercode hier 
veröffentlichen.

Wiegesagt baut diese Funktionsart auf einer anderen Idee auf "und 
theoretisch sehe ich in diesem Programmiercode auch keine Probleme"

Bis dann

Autor: frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in bascom basic genügt ein befehl.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
frank wrote:
> in bascom basic genügt ein befehl.


Kann man auch den Quelltext sehen, der hinter diesem Befehl steckt ?

Wäre nämlich sehr wichtig, um festzustellen, ob und wie fehlertolerant 
dieser Befehl ist (Parity-Check, Timingcheck, Störungsüberbrückung 
usw.).



Peter

Autor: frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
alle checks werden gemacht kannst dir ja das lib file anschauen

habe schon eine uhr am laufen mit uhr und wecker + temperaturanzeige und 
funkübertragen mit Kaffeemascine an.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
frank wrote:
> alle checks werden gemacht kannst dir ja das lib file anschauen

Welches Lib-File ?

Kannst Du es schicken ?

Natürlich nur, wenn es auch Quelltext ist, im Objektformat kann man ja 
nichts erkennen.


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaub, ich habs gefunden:

http://www.roboternetz.de/wissen/index.php/DCF77-D...

Ist aber alles in Assembler, da braucht man ne Weile zum Durchsteigen.


Peter

Autor: frank (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
dcf77.lib ist im copiler verbaut den dcf77.bas code habe ich aus irgent 
einem forum gesaugt mist muss mal meine favorieten checken.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Programmiercode werde ich erst dann veröffentlichen, wenn dieser 
auch läuft.........

Aber zu 99,99% ist er lauffähig.

Autor: Rechtschreibwächter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
frank wrote:

> dcf77.lib ist im copiler verbaut den dcf77.bas code habe ich aus irgent
> einem forum gesaugt mist muss mal meine favorieten checken.

Ist Dein Programm ähnlich sorgfältig geschrieben wie Dein Posting?

Autor: Rechtschreibwächter nein danke (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wer Rechtschreibfehler findet darf sie aufheben und behalten

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.