www.mikrocontroller.net

Forum: Compiler & IDEs DCF77 Uhr von U.Radig


Autor: Pascal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe für eine Funkuhr den DCF77 Code von der Webseite ulrichradig.de 
genommen. Dieser funktioniert auf einem ATmega8 auch wunderbar. Ich 
möchte jedoch statt der Lokalzeit die Zeit in UTC (GMT) ausgeben, da ich 
wenig C Kentnisse habe fällt mir das aber recht schwer. Zunächst habe 
ich einfach 2 Stunden von der Variablen hh abgezogen, da kamen aber 
immer wieder seltsame Zeiten bei heraus. Ausserdem wäre das nicht schön, 
da ich so zur Uhrzeitumstellung immer wieder die Zeitdifferenz 
umprogrammieren müsste oder den Atmega8 austausche...
Ich habe gesehen, dass im Zeitcode des DCF77 die Bits 17 und 18 die 
Information MEZ oder MESZ angeben. Wie komme ich nun im Quellcode an die 
Information der beiden Bits dran und wie kann ich dementsprechend daraus 
mir die UTC Zeit errechnen?
Wer kann mir geeignete Denkanstöße bzw. Hilfestellungen geben.

Grüße

Autor: Hilfesteller (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jemand, der Lust hat, sich für dich den Quellcode zu organisieren und 
nachzuvollziehen.

Autor: Pascal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein! Ehrlich? Wow - hätte ich jetzt nicht gedacht - Spaß beiseite: Mag 
denn jemand sinnvolle Hilfen geben und schreibt auch die Ansätze oder 
nicht?

Grüße


P.S.: Da will man einmal was selbst machen und nur nach Hilfestellungen 
bzw. Ideen oder Stichwörtern und nicht der Lösung fragen und da kommen 
so geniale Antworten die null konstruktiven Inhalt besitzen. Man sollte 
doch mal drüber nachdenken ob in einem technischen Forum eine solche Art 
der Beanwortung sinnvoll ist...

Autor: Wolfgang Horn (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi, Pascal,

würdest Du meinen Stundensatz zahlen, dann würde ich mich mit Freude in 
den Quellcode stürzen und Dir die Lösung präsentieren.

Aber wie alle Fragesteller hier zahlst Du keinen Stundensatz. Warum soll 
ich mir Mühen machen für eine Lösung, die Du bei etwas mehr Übung in C 
selber herausfinden könntest?

Ulrich Radig hat sein Programm gut kommentiert, Deine Frage zu 
beantworten kostet nur Mühe. Wenn Du dazu nicht bereit ist, wazu sollte 
ich es sein?

Deine "beleidigte Leberwurst-Antwort" mit "man sollte mal drübe 
nachdenken" weise ich als Unverschämtheit zurück.

Mit solchen Unverschämtheiten wirst Du hier keine Freude haben.

Ciao
Wolfgang Horn

P.S. In dem Programm, das ich von Ulrich kopiert habe, ist "hh" 
deklariert als unsigned char. Wenn Du 1 - 2 rechnest, kommt kein 23 bei 
raus, sondern 255.

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>würdest Du meinen Stundensatz zahlen, dann würde ich mich mit Freude in
>den Quellcode stürzen und Dir die Lösung präsentieren.

Er ist aber nicht in deinen Betrieb gekommen um Hilfe zu bekommen, 
sondern in ein MC-Forum.
Wenn du nicht helfen willst, schreib doch einfach garnix.

Oder hast du einfach zuviel Zeit dich in Foren rumzutreiben und deinen 
Frust abzulassen weil niemand deinen Stundensatz zahlen will ?

Autor: Stephan Storm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jürgen: Du sprichst mir aus der Seele. Es gibt in so vielen Foren Leute 
die unglaublich viele Beiträge schreiben aber nichts sinnvolles 
Anzubieten haben.

@Pascal: Naja du hättest den Code schon mitliefern können. So müssen wir 
extra danach suchen...

Hier ein Vorschlag. "//Anpassen der gewünschten..." ab da isses neu. Der 
Rest ist aus clock.c.
//Berechnung der Stunden BCD to HEX
    hh = rx_buffer->Hour-((rx_buffer->Hour/16)*6);
    //Berechnung des Tages BCD to HEX
    day= rx_buffer->Day-((rx_buffer->Day/16)*6); 
    //Berechnung des Monats BCD to HEX
    mon= rx_buffer->Month-((rx_buffer->Month/16)*6);
    //Berechnung des Jahres BCD to HEX
    year= 2000 + rx_buffer->Year-((rx_buffer->Year/16)*6);
    //Sekunden werden auf 0 zurückgesetzt
    ss = 59;
    flags.dcf_sync = 1;

    // Anpassen der gewünschten Zeitzone. zz gibt die Verschiebung in
    // Stunden an.
    if(hh < zz)
    {
      hh = (24 - (zz - hh));
      //...Datum anpassen...
    }
    else
    {
      hh -= zz;
    }

    }
else...

Müsste klappen... Wenn du das MEZ/MESZ Bit haben willst machst du am 
besten sowas:
unsigned char mesz;
mesz = dcf_rx_buffer & (1<<17);

Das müsste das MESZ Bit 17 im Signal liefern. Alternativ kannst du die 
Struktur abändern.

Ich hoffe ich konnte helfen
Stephan

Autor: Pascal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jürgen,
Hallo Stephan,

vielen Dank für Eure Antworten und das Verständnis. Ich dachte schon im 
Internet läuft jetzt nichts mehr richtig...

Ich habe den Quellcode nicht dabeigeschrieben bzw. kopiert da ich nicht 
wusste ob ich das machen darf wegen Copyright usw - ist ja nicht mein 
geistiges Eigentum...

@Stephan:
Ich habe den Schnipsel mal so darein getan, jetzt bekomme ich nur noch 
einen Fehler, hab auch mal danach gesucht, da heißt es ich muss 
irgendwie den Wert "Casten" - habe aber keine Ahnung was es mir sagen 
soll, habe mal in einem Tutorial danach gesehen verstehe aber absolut 
nichts was die von mir wollen.

Also, der Compiler sagt mir dieses:

../clock.c:75: warning: left shift count >= width of type

In der Zeile 75 steht das:
    mesz = dcf_rx_buffer & (1<<17);

und ganz oben in clock.c habe ich ergänzt
//Mitteleuropäische Sommerzeit oder nicht
volatile unsigned char mesz;

//Zeitverschiebung in Uhrzeit einrechnen - Wert in Stunden
volatile unsigned char zz;

Dachte jetzt einfach irgendwie das nach diesem System hier einzurechnen:
    flags.dcf_sync = 1;
    
    //Anpassen der gewünschten Zeitzone, zz gibt die Verschiebung 
    //in Stunden an

    mesz = dcf_rx_buffer & (1<<17);

    if (mesz = 0)
    {
      zz == 1; //minus 1 Stunde Verschiebung nach UTC wenn
           //Winterzeit
    }
    else
    {
      zz == 2; //minus 2 Stunden Verschiebung nach UTC wenn
           //Sommerzeit
    }
    
    if (hh < zz)
    {
      hh = (24 - (zz - hh));
    // .. Datum noch anpassen .. -- ToDo !!!
    }
    else
    {
      hh -= zz;
    }
    }
  else ....

Was mache ich noch falsch oder wie muss ich besser gesagt mesz 
deklarieren damit das nicht mehr einen Fehler gibt?

Grüße und nochmals DANKE!
Pascal

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> if (mesz = 0)

Sollte wohl eher
 if (mesz == 0) 
heissen

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pascal schrieb:

> Also, der Compiler sagt mir dieses:
> ../clock.c:75: warning: left shift count >= width of type

Damit sagt er dir, dass ein "int" nur 16 Bits hat, 1<<17 also Unsinn 
ist.

Autor: Pascal (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@A.K.
Ja, soweit verstehe ich es mittlerweile auch, aber auch ein volatile 
long long mesz; bringt mir keinerlei Änderung, dann müsste doch 
eigentlich alles reinpassen?

@STK500-Besitzer
Klar, Tippfehler.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Standardfehler. Quizfrage: Welchen Datentyp hat der Ausdruck 1<<17 ? 
Kleiner Tip: Die Frage ist direkt so beantwortbar, ohne den Kontext zu 
kennen und auch nicht vom Prozessor oder Compiler abhängig.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Standardfehler. Quizfrage: Welchen Datentyp hat der Ausdruck 1<<17 ?

Der Datentyp nützt Dir bloß nichts, der Ausdruck ist compilerabhängig:

Auf nem 32-Bitter wird der Ausdruck das gewünschte Ergebnis liefern.
Auf nem 8- oder 16-Bitter ist er 0.


Peter

Autor: Pascal G. (pascalg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm, schöne Sache, stehe im Dunklen. Was muss ich machen um den Fehler 
nicht mehr zu bekommen, selbst ein long long bringt keine Abhilfe!?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

>> Standardfehler. Quizfrage: Welchen Datentyp hat der Ausdruck 1<<17 ?
> Der Datentyp nützt Dir bloß nichts, der Ausdruck ist compilerabhängig:

Im Gegenteil. Zwar ist das Ergebnis abhängig vom Compiler, aber der 
Datentyp und dessen Wertebereich sind dabei die entscheidenden Faktoren. 
Aber nur der Wertebereich ist abhängig vom Compiler, der Typ nicht.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Pascal G. schrieb:

> Hmm, schöne Sache, stehe im Dunklen. Was muss ich machen um den Fehler
> nicht mehr zu bekommen, selbst ein long long bringt keine Abhilfe!?

Ich versuche gerne, Leute zum selber denken zu bewegen. Aber wenn das 
nicht funktioniert: Ein Ausdruck a<<b mit a und b vom Typ "int" ist 
immer auch vom Typ "int", egal was dabei als Ergebnis rauskommt und egal 
ob a und b Konstanten sind oder nicht. Eine numerische Konstante wie 1 
ist vom Typ "int". Also ist 1<<17 auch "int", aber darin bei 16 Bits 
nicht darstellbar.

Der Standardfehler liegt in der Annahme, dass in einem Statement
  long x = a << b;
der Typ "long" Auswirkung auf die Rechung rechts davon hätte. Hat er
nicht. Da wird erst gerechnet und danach - zu spät - in "long" 
konvertiert. Der Datentyp des Ausdrucks a<<b und daher auch das Ergebnis 
sind unabhängig davon, in welchem Kontext das steht.

Also: 1L<<17 verwenden.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tipp: Probiert es mal in der folgenden Art:
mesz = (dcf_rx_buffer >> 17) & 1;

Wenn die Abfrage nur auf == und != 0 stattfindet, ist es egal, an 
welchster Stelle das Bit ist.

Oder schaut einfach mal nach, wie die Variable dcf_rx_buffer definiert 
ist...

Grüße,

   Martin

Autor: Stephan Storm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Sorry. Natürlich klappt das nicht. Wie schon gesagt wurde ist eine Zahl 
im Compiler automatisch ein Integer und eben nur 16 Bit breit. Casten 
bedeutet, dass der Compiler wenn möglich z.B. aus einem 16-Bit Integer 
ein 32/64-Bit Long macht. Folgendes funktioniert jetzt. Habs getestet:
mesz = dcf_rx_buffer & ((long)1<<17);

Das (long) ist der Cast.

Das ist aber extrem krass ;-D. Deswegen machs einfach direkt mit einem 
32Bit Wert.
mesz = dcf_rx_buffer & 0x20000;

Bis denn
Stephan

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist daran krass? (long)1 ist übrigens identisch mit 1L. Und der 
Compiler rechnet das selber, so dass zwischen 1L<<17 und 0x20000 kein 
Unterschied besteht, aber 1L<<17 ist verständlicher.

Autor: Stephan Storm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geschmackssache.

Autor: Pascal G. (pascalg)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute!

Erstmal Danke für die schöne Diskussion und die vielen Ideen usw. Ich 
habe heute endlich Zeit gefunden das ganze einmal auszuprobieren.
Ich habe leider noch nen Fehler drin, denn irgendwie erkennt der aus Bit 
17 bzw. 18 des DCF Signals noch nicht das Sommerzeit ist. Habe mal den 
Sourcecode mit dabeigetan, vielleicht findet ihr ja den Käfer in der 
clock.c oder main.c?!?
Ausserdem habe ich jetzt noch das Problem, dass auf der seriellen 
Schnittstelle der Text nicht mehr im Sekundentakt "sauber" geschrieben 
wird, es wird immer mal eine Sekunde in der Anzeige übersprungen. Habe 
schonmal mit dem Wert
    //Wait a short time
    for (long i=0;i<50000000;i++){};
ein wenig gespielt und auch die Geschwindigkeit der seriellen 
Schnittstelle auf 38K4 hochgesetzt, bringt aber auch nichts. Dazu auch 
irgendwelche Ideen?

Grüße Pascal

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

Bewertung
0 lesenswert
nicht lesenswert
Pascal G. schrieb:

> Ich habe leider noch nen Fehler drin, denn irgendwie erkennt der aus Bit
> 17 bzw. 18 des DCF Signals noch nicht das Sommerzeit ist.

Tja
    mesz = dcf_rx_buffer & (1L<<18);

maskiert aus dcf_rx_buffer nur das interessierende Bit frei.
Dieses Bit ist nach wie vor an Bitposition 18.
Wenn du diesen long wert danach an einen unsigned char zuweist, werden 
alle Bits, die überzählig sind, also alles von Bit 8 an aufwärts, 
einfach weggeschmissen. Und damit ist dann auch das dich interessierende 
Bit Geschichte.

Wenn du haben willst, dass mesz entweder 0 oder 1, ist je nachdem ob das 
Bit gesetzt ist oder nicht, dann sei explizit (Das empfiehlt sich 
sowieso immer für einen Anfänger)
   if( dcf_rx_buffer & (1L<<18) )
     mesz = 1;
   else
     mesz = 0;
Dann klappts auch mit der Sommerzeit

Wenn dich dann die C-eritis gepackt hat, kannst du das auch kürzer 
schreiben
   mesz = ( ( dcf_rx_buffer & (1L<<18) ) != 0 );
aber für den Anfang ist ein explizites if sicherlich einfacher zu lesen.

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

Bewertung
0 lesenswert
nicht lesenswert
Pascal G. schrieb:

> wird, es wird immer mal eine Sekunde in der Anzeige übersprungen. Habe
> schonmal mit dem Wert
>
    //Wait a short time
>     for (long i=0;i<50000000;i++){};
> 
> ein wenig gespielt und auch die Geschwindigkeit der seriellen
> Schnittstelle auf 38K4 hochgesetzt, bringt aber auch nichts. Dazu auch
> irgendwelche Ideen?

Ja.
Schmeiss den Müll raus und mache den Update, wenn sich die Sekunden 
verändert haben.

int main()
{
  ...
  unsigned char old_ss;

  ....

  old_ss = 255;

  //Ausgabe der Zeit auf der Seriellen Schnittstelle und dem LCD in einer Endlosschleife
  while (1)
  {
    if( ss != old_ss )
    {
      usart_write("%2i-%2i-%4i Time: %2i:%2i:%2i Sync: %i  Rx: %i  MESZ: %i       \r",
        day,mon,year,hh,mm,ss,flags.dcf_sync,flags.dcf_rx,flags.dcf_mesz);
    
      lcd_print(0,0,"%2i.%2i.%4i RX: %i",day,mon,year,flags.dcf_rx);
      lcd_print(1,0,"%2i:%2i:%2i SYNC: %i",hh,mm,ss,flags.dcf_sync);
    
      old_ss = ss;
    }
  }  

Autor: Pascal G. (pascalg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo K.H. Buchegger,

vielen Dank für Deine tollen Antworten, darauf wäre ich nie gekommen. 
Ich glaube ich muss mich mal tiefer mit der C Programmierung 
beschäftigen. Gibt es da speziell für diese Bedürfnisse ein gutes 
Tutorial oder Buch wo alles nacheinander erklärt wird so das man es ohne 
große Kenntnisse versteht aber trotzdem nicht langwierig wird?

Wegen den Updates der Daten auf der Schnittstelle / dem LCD:
Jetzt in dem Style kommt das Update nur alle 2 Sekunden!? Soll ich da 
irgendwie noch einen Timer Interrupt wirken lassen oder so damit es 
besser klappt?

Grüße

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

Bewertung
0 lesenswert
nicht lesenswert
Pascal G. schrieb:

> Wegen den Updates der Daten auf der Schnittstelle / dem LCD:
> Jetzt in dem Style kommt das Update nur alle 2 Sekunden!? Soll ich da
> irgendwie noch einen Timer Interrupt wirken lassen oder so damit es
> besser klappt?

Ich denke, die Ausgabe an sich dauert schon zu lange. Du gibst ziemlich 
viel über die UART/LCD aus und das ist nicht gerade das schnellste.
Kürze die Ausgabe etwas zusammen (bzw. gib am LCD tatsächlicgh nur die 
Dinge aus, die sich auch verändert haben. Tag, Monat, Jahr verändern 
sich praktisch nie, werden aber jede Sekunde erneut aufs Display 
formatiert. Das muss nicht sein und würde Zeit sparen. Selbiges für 
Stunden und Minuten

Ach ja, da sollte man noch einmal umdrehen
    if( ss != old_ss )
    {
      old_ss = ss;

Autor: Pascal G. (pascalg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

also meine DCF77 Uhr läuft nun seit ein paar Wochen ohne weitere 
Probleme. Ich habe nun die letzten Tage probiert mit der oben erwähnten 
lib von U.Radig im CGRAM des LCD eigene Zeichen zu generieren (will den 
DCF77-Sync mit einer Art Antenne darstellen). Dazu habe ich probiert mit 
lcd_write etwas zu machen, leider kann ich sobald ich da irgendwas sende 
nur noch wirre Zeichen auf dem Display sehen. Eignet sich denn die Radig 
Lib dazu eigene Zeichen (acht Stück laut Datenblatt) ins Display zu 
schreiben? Falls ja, wie macht man das? Die Suche brachte mich immer nur 
auf Seiten mit Assembler-Code.... Ausserdem wollte ich ungern die Radig 
Lib gegen eine andere austauschen...

Grüße

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.