Ein für sich unabhängiger, in nur 112 Words formulierter AVR-Assemblerbaustein zur Dekodierung des DCF77-Signals & zur Verwendung in eigenen Programmen sei an dieser Stelle vorgestellt. Das gute Stück ist allein in 10 mSek. Zyklus aufzurufen, übergibt die Zeitinformation nach erfolgreichem Empfang BCD-codiert und stellt die Sekunden-Zelle einer optionalen, zuvor aufzurufenden Software-RTC sowie sinnvollerweise auch deren 1/100 Sekunden-Zelle (zur Vermeidung kurzer Sek.Sprünge) bei Minutenwechseln zurück. Impulslängen-, Paritäts- und Bitvollständigkeitsprüfung machen den Baustein zuverlässig, die Tolerierung gewisser (definierbarer) Impulslängen-Ungenauigkeiten sowie ggf. kurz nachfolgender Störspikes sehr robust. Habe diesen Decoder zusammen mit dem berühmten Conrad-Modul in Betrieb. Das Sensibelchen ist noch dazu in relativ schlechter Empfangslage, über mehrere Meter und mit nicht ganz sauberer Spannungsversorgung angebunden... Freue mich über weitere Anregungen/Verbesserungsvorschläge! Gruss Pit
Achtung! Initialisierungsroutine enthielt noch einen kleinen Fehler (hatte ich selbst nicht vorab verwendet). Jetzt dürfte es aber passen. Pit
Schut gut aus! Werde das bei gelgeheit mal testen, nur eins würde ich noch sagen, mach das doch so, das du den benötigten pin noch per DEF .def DCFPORT = PORTB; .def DCFPIN = 1; noch einfügst :)
Ach ja ein Tiny+das DCF Modul von Reichelt solte doch dafür geeigent sein oder wird irgenwelche Spezillen eigenschaften beim AVR benötigt?
Hallo Pit, ich habe noch ein Verständnisproblem zum Code. In der anhängenden Datei habe ich einige Stellen rot markiert, an denen nach unbedingten Sprüngen (rjmp) Programmcode nicht mehr erreichbar ist? Gruß Joachim
das sind doch "skip if bit set..." Befehle,(die PICs arbeiten NUR mit sowas) d.h. der nächste Befehl wird übersprungen wenn die Bedingung zutrifft, das braucht kein Label an der folgenden Zeile.
@joachim: die eine sprungmarke (dcf77_13) ist tatsächlich überflüssig. stammt noch aus der zeit von codeentwicklung & -optimierung. ansonsten schau doch bitte mal in der doku nach, was sbis bzw. sbrc tatsächlich bedeuten. vermutlich gehst du davon aus, hier würden irgendwelche bits gesetzt... @läubi: das dcf-modul von reichelt kenne ich nicht. es dürfte aber keine probleme geben, wenn nur hinten die dcf77-typische impulsfolge mit ausreichendem pegel rauskommt. bitte aber die polarität beachten und ggf. im programm anpassen. ansonsten ist der code auf jedem avr lauffähig, der noch einen portpin und ein paar bytes sram frei hat. der 10 millisekunden-aufruftakt sollte auch hinreichend stabil sein. gruss pit
Hier ist auch ein kurzer Assemblercode (96 Worte): http://www.mikrocontroller.net/forum/read-4-23408.html#new Zusätzlich ist noch ne Uhr drin, die bei Fehlern oder Ausfall des Signals weiterläuft. Peter
< http://www.reichelt.de/artikeldruck.html?ARTIKEL=DCF77%20MODUL > Hört sich doch vernünftig an. Dann brauch ich nurnoch einpassendes Display und ein wenig Geld :-\ und schon kanns losgehen ;)
@peter: hatte schon vermutet, dass du dich hier einschalten wirst :-)) aber bitte nicht schummeln: die dcf77-receive funktion in OVF0INT.inc darfst du ruhig mitzählen... trotzdem ein elegantes programm für den, der die komplettlösung sucht. ich selbst wollte mal ohne eine fette datentabelle auskommen. @läubi: viel erfolg! gruss pit
@Pit, stimmt, da sind noch 26 Worte im Interrupt. Wenn man beides zusammenpackt, könnte man noch was einsparen. Die Dekodierung braucht ja nicht soviel Rechenzeit. Aber ich versuche bei den AVRs die Interrupts so kurz wie möglich zu halten. Auch habe ich es lieber, wenn die Zahlen binär vorliegen, das rechnet sich leichter als 2 Dezimaldigits gepackt (packed BCD). Peter
@peter für meinen teil sollte ich vielleicht auch noch in rechnung stellen, dass die unabhängigkeit des bausteins natürlich seinen tribut fordert. sprich jene zusätzliche words, die lds/sts für ihre arbeit mit dem sram nun mal benötigen. wenn sich das noch irgendwie mit einem pointer behandeln ließe, könnte man den speicherbedarf der programmfunktionaliät womöglich unter 100 words drücken. binär ist die handhabung der variablen sicher leichter. wer's braucht, kann die routine "erfolgreicher empfang" dahingehend ergänzen. die 112 words dürften aber dann leider nicht mehr zu halten sein. gruss pit
das gute liegt doch so nah: ersetzt man alle lds/sts durch ldd/std unter zusätzlichem einsatz des y-pointers, lässt sich noch beachtliches sparen. wer schliesslich anfangs auf die initialisierungsroutine verzichten kann (weil z.b. das sram vorher aus anderer quelle initialisiert wird) kann die ersten zwei zeilen der dcf77_init dann noch durch ein gepflegtes movw ZL:ZH,YL:YH ersetzen. da waren es tatsächlich nur noch 99... pit
für alle DCF77 interressierten ein Tip http://www.progforum.com/showthread.php?t=5896 das mdol ist separat und gibt ein sehr gutes Signal
lol gibts die noch immer??? Naja hab schon 4 zu hause rumfliegen einer komplett im einsatz und einer eingepackt und 2 auseinander die laufen auch mit 5V..
Hallo, ich habe meinen DCF-Dekoder nun auch fertig. http://www.mikrocontroller.net/forum/read-4-248219.html?reload=yes#289255 Das Programm ist in C und Assembler geschrieben. Die Abtastung des Signals erfolgt recht störsicher. Die Anschaltung des Empfängers mache ich über eine Stromschleife. Das hat den Vorteil, daß ich eine lange zweiadrige Klingelleitung für Betriebsspannung und Zeitzeichensignal verwenden kann und den Empfänger (ohne Batterie) am günstigsten Empfangsort aufstellen kann. Die erste Dekodierung erfolgt im Durchschnitt 20s schneller als bei anderen Lösungen. Speicheroptimiert ist das Programm allerdings nicht... Gruß Joachim
Nachtrag: Die Polung (normal bzw. invertiert) des DCF-Signals ist unerheblich. Der Dekoder stellt das fest.
Hallo Joachim, und welcher DCF Baustein benutzt Du ? Ich habe bei meiner Propeller-Uhr den von Conrad, aber ehrlich gesagt, ist das Teil sowas von sch..., außer man richtet es irgendwie Richtung Mainflingen aus. Ich habe zwar jetzt schon 4 von diesen Uhren mit dem Conrad Modul gebaut, aber mich würde schon interessieren, ob es am Modul oder der Software liegt, obwohl ich eher zum ersteren tendiere, da ich mittels LED's die empfangenen Interrupts ausgebe und wenn die Uhr nicht korrekt ausgerichtet ist, flackerts wie wild. Dreh ich sie richtig, dann sehe ich den Sekundenimpuls mittels der LED's. Viele Grüße, Peter
Hi! Es liegt an der sch... Antenne des Moduls. 1. meistens schlecht abgeglichen 2. schlechte Kondensatoren im Schwinkreis Nimm einen Ferritstab mit Mittelwellenspule und gleiche sie mit guten C's auf 77,5KHz ab. Dann sollten deine Probl. aus der Wellt sein. MFG Uwe
Hallo Peter, ich habe einen Funkwecker von Aral zerlegt. War mit 3 Euro und einer Sammelkarte recht preiswert zu erstehen. Ich werde den Empfänger später auf dem Dachboden platzieren. Da habe ich Ruhe vor den "Störern" im Haus. Gruß Joachim
Hallo Uwe, danke für den Tipp :) Als Kondensatore(n) fällt mir jetzt nur diese eine ein, der auf der Antenne draufklebt. Ist das der einzige den man erst mal abgleichen könnte, bevor man sich eine komplett neue Antenne baut ? Merci
Hi, petersch, die Spule auf der Ferritantenne bildet mit dem Kondensator dabei einen Schwingkreis, und nur auf dessen Resonanzfrequenz empfängt das Ganze. Dieser Schwingkreis muß auf 77,5 kHz abgestimmt sein. Wie, wenn man die Meßmittel eines Funkamateurs nicht hat und auch nicht die aus dem Labor der Uni? Einfach- such Dir einen beim nächsten Treffen des Ortsvereins des DARC. Oder den nächsten Meister, der Radios noch selbst repariert - falls es das überhaupt noch gibt. Nähere Infos: http://www.darc.de/ardf. Mit zu den größten Problemen beim DCF77-Empfang gehören die Störungen durch Fernseher, die fünfte Oberwelle der Zeilenfrequenz liegt nur 625 Hz oberhalb der 77,5 kHz - und kann Vorstufe und Empfänger völlig zustopfen. Das Optimum wäre ein Quarzfilter direkt an der Ferritantenne, aber wer sucht schon das Optimum... Ciao Wolfgang Horn
Hi! @Wolfgang, Einen Frequenzgenerator haben eigentlich viele Bastler, auch eine vernünftige Werkstatt sollte sowas haben. >die fünfte Oberwelle der Zeilenfrequenz liegt nur 625 Hz oberhalb >der 77,5 kHz - und kann Vorstufe und Empfänger völlig zustopfen. Das ist ja richtig, aber eine hohe Güte und damit ein "scharfer" Schwinkreis helfen da schon recht ordentlich. Der Fernseher stört meinen Empang eigentlich nicht. Er steht 2m "vor" meiner Antenne in Richtung DCF-Sender gesehen. > Das Optimum wäre ein Quarzfilter direkt an der Ferritantenne, aber > wer sucht schon das Optimum... Ich, wenn es nicht zu aufwändig ist. @petersch, ja der ist das, gegen guten tauschen und abgleichen hilft schon. Nur der Ferritstab ist bischen klein. Viel Erfolg, Uwe
Hi, ich habe versucht den DCF-Programmbaustein mit in das Programm für einen ph-Controller (Aquariumsteuerung) aufzunehmen. Leider werden aber nur unsinnige Werte für Datum und Uhrzeit (keine ini-Werte) auf dem Display angezeigt. Das DCF-Modul von Conrad scheint aber korrekt zu arbeiten, denn ich kann mit dem Oszi am Pin entsprechende Pegel sehen. Kann mir jemand helfen? Gruß Raik
Hallo Raik, die Initialisierung des Bausteins machst du schon mal doppelt. Und verzichte doch mal zunächst auf dessen Aufruf. Werden nun ordnungsgemäss die Ini-Werte angezeigt ?
Hallo Ralf, leider konnte ich keinen doppelten Aufruf der Initialisierung des dcf-Moduls finden. Ohne Initialisierung habe ich noch nicht getestet. Ansonsten funktionieren alle anderen Menüpunke des Programms ohne Probleme. MfG Raik
Hallo Raik, schau doch mal genau: den Speicher, den der Baustein belegt, initialisierst du doppelt. Einmal du selbst, einmal über dcf77_init. Und wo werden eigentlich die Zellen HSEK-JHR von dir initialisiert? Der Baustein macht das jedenfalls nicht von selbst. Klar, dass dann da zufällige Werte stehen. Dieser Bereich soll übrigens von einer RTC betrieben werden. Der Baustein schreibt da bei erfolgreichem Empfang nur bei jedem Minutenwechsel die Zeitinformation hin... Gruss Ralf
Hi, @ Ralf, ich habe jetzt eine Soft-RTC mit eingefügt. Außerdem verwende ich nun eine dcf-Auswerteroutine, die von Peter schon vor einiger Zeit veröffentlicht wurde. Die Initialisierungswerte werden zwar jetzt korrekt im Sekundentakt hochgezählt, aber die aktuelle Uhrzeit wird noch immer nicht erkannt. Außerdem wird mir angezeigt, daß eine neue Sekunde erkannt wurde (newsecond -> Anzeige *). Beim Abklemmen des DCF-Empfängers verschwindet die Anzeige newsecond und die Datenpakete werden verworfen (dcf77error -> Anzeige E). MfG Raik
Hallo @Raik.. ich baue mir selbst grade einen Aquacomp mit Zeitschaltuhr, Heizung, PH und Leitwertmessung und bei mir traten dieselben Probleme auf. Hab das in C (CAVR) geschrieben und bei mir läuft es recht zuverlässig. Vieleicht hilft es dir ...schreib mal wenn du noch fragen dazu hast. mfg Ulli
muss noch etwas hinzufügen, damits ein Reim wird.. also als µC nehme ich hier einen Mega8535 und im Hauptprogramm werden diese beiden Interrupts eingesetzt: //--------------------------------------------------------- // Timer 2 output compare interrupt 64µS interrupt [TIM2_COMP] void timer2_comp_isr(void) { dcf_tim2(); } //--------------------------------------------------------- // External Interrupt 0 service routine Steigende Flanke interrupt [EXT_INT0] void ext_int0_isr(void) { dcf_int0(); } //---------------------------------------------------------- *Timer 2 ist folgendermaßen eingestellt: // Timer/Counter 2 initialization ASSR=0x00; TCCR2=T2_PRESCALE; TCNT2=0x00; OCR2=(T2_CTC * RATE_FAKTOR) - 1; // ctc & interrupt bei 24 (0...24) // Timer(s)/Counter(s) Interrupt(s) initialization //TIMSK=0x02; //timer 0 enabled TIMSK=0x82; //Timer Interrupt 0 + 2 an also versuch mal das in deinen Programm einzubauen :-)
Hi Pit, funktioniert ja super. Allein einfache Binärvariablen für's Zeitformat hätte ich mir noch gewünscht, vielleicht hast Du ja dafür noch irgendwann einmal eine effiziente Lösung parat! MfG Robert Sommerfeld
@Ulli bzw. @Raik Ich bin eben über diesen Thread gestolpert und möchte mir auch so einen kleinen Aquariencomputer bauen. Hat sich bei euch schon was getan - sprich wie weit seid ihr jeweils mit eurem Projekt? Grüße Michi
@ Michi leider habe ich momentan wenig Zeit am diesem Projekt weiter zu arbeiten. Die Probleme mit der fehlerhaften DCF-Anzeige bestehen aber immer noch. Vielleicht kannst Du mir ja noch einige entscheidende Hinweise geben. MfG Raik
hallo ich möchte diesen Baustein auch verwenden. Dazu einige Fragen: kann man auch ein invertiertes Signal mit einbauen? Mit Xor zwar kein Problem, aber die Erkennung, ob ein Empfänger angeschlossen ist, sehe ich dann als Problem. Wie kommen die angegebenen Timing-Zahlen zustande? Bei 180 und 10ms müßten 1,8 sek. rauskommen. Wo die Zeit zwischen 100ms und 200 ms abgefragt wird, kann ich nicht erkennen. Ich wollte statt 10ms 8ms als Aufruffrequenz verwenden (8bit Timer) und da konnte ich nicht finden, an welcher Stelle ich da was verändern muß. mfg
Hallo, für ein invertiertes DCF77-Signal ist in Zeile 5 sbis durch sbic PINX,Y zu ersetzen. Mit 10 mSek. Aufruftaktzyklus lassen sich Impulszeiten von 100/200 mSek. naturgemäß am besten teilen bzw. abzählen. Nicht vergessen, daß aber nicht die eigentlichen Impulse sondern die Pausenzeiten dazwischen zur Bestimmung des jeweils vorherigen Bits abgemessen werden. Klar geht das auch mit 8 mSek Takt zu erfassen, zumal die Impulszeiten sowieso ziemlich verschmiert sein können. Dazu sind die Konstanten für die lange letzte sowie alle anderen Pausenzeiten einfach je nach Aufruftakt (wobei 10 MSek eher eine obere Grenze ist) anzupassen. Ergibt sich eigentlich alles aus Quelltext+Beschreibung. Gruß Pit
danke, da muß ich mich erst noch etwas einarbeiten. Hab das mit den Pausen messen auch festgestellt und hab den vermutl. Grund gefunden. Am Anfang wird festgestellt, ob ein Empfänger vorhanden ist mit Pause >2 sek. Bei 8ms Takt ist das schon etwas knapp, aber vielleicht noch ausreichend. Würde das gehen? Ich bin jetzt dabei, das Programm auf Interrupt und Mainloop aufzuteilen, damit die ISR so wenig wie möglich Zeit verbraucht. Wegen der Sprünge ist das allerdings nicht so einfach. Das Umspeichern und INIT könnte z.B. in die Mainloop. Auch die ganze Auswertung könnte dahin. Ich habe am Anfang folgendes gesetzt. ldi pol,$FF ; Pol= FF=low-aktiv, 00=high-aktiv lds r20,DCF77CT ;alle 10 mSek. aufzurufen lds r21,DCF77CHECK ldi temp2,1<<pinb0 ; 0x0 eor temp2,pol ; andi temp2,1<<pinb0 ; 0x0 in temp,PINB ; Port eor temp,temp2 ; sbrs temp,PinB0 ;Input-Pin Der Grund ist, daß alle möglichen Änderungen am Anfang des Programms stehen sollen. Ich finde meine Ergänzung allerdings etwas umständlich. ich habe vor ca. 15 Jahren eine serielle PC Funkuhr gekauft. Kostete ca. 50,- DM. Ich möchte diese an den Mega32 anschließen. Weiß jemand die Kontaktbelegung von dieser Uhr. Mit dem mitgelieferten Programm wird die Stromversorgung über die serielle Schnittstelle eingeschaltet. Das Signal muß ja auch nicht unbedingt über Tx rauskommen. Das Wichtigste ist aber die Stromversorgung. Das übrige könnte ich wahrscheinlich messen. Bei der Funkuhr von C habe ich nur den Batteriebetrieb mit 1,5V gesehen. Da kann doch dann kein TTL Signal rauskommen. Deshalb hatte ich diese Uhr nicht weiter beachtet, zumal die mir auch recht teuer erscheint. mfg
ich habe jetzt mal dieses DCF Programm mit einem anderen verglichen.
Arbeitsweise: anderes Programm: bits werden nur gelesen und in Reg.
gespeichert. Am Ende der Min. erfolgt die Interpretation: Parityprüfung,
Fehlerbits setzen, Schieben und Speichern. Dies hat den Vorteil, daß der
größere Teil in die Mainloop gelegt werden kann. Trotzdem war das Ganze
wegen zusätzlicher Sachen unübersichtlich, was eigentlich nicht
notwendig ist und der Registerverbrauch war auch zu hoch.
Bei Pit: Das Ganze liegt in der ISR und kann durch Ergänzung von Push
und POP der 4 Register und Ersetzen von ret durch reti angewendet
werden. Da der Interrupt verhältnismäßig lange gesperrt bleibt, kann das
Programm hauptsächlich nur als Standalone verwendet werden und das ist
nicht sinnvoll. Darum versuche ich eine Aufteilung. Im Interrupt müßten
2 bits gesetzt werden. Ein Fehlerbit und ein "Minute noch nicht zu Ende"
bit. Im Main werden diese abgefragt: Bei Fehler, Init und überspringen,
bei dem anderen bit Umspeichern, Init. So wären Umspeichern und Init aus
der ISR raus. Leider kann ich das in dem Programm nicht so erkennen, wie
das abläuft.
Zur Diskussion wäre zu stellen, ob nach einem Fehler abgebrochen wird
und eine volle gültige Min. erkannt werden muß oder gültige Teile
beibehalten werden. Die Beibehaltung könnte eine schnellere gültige
Vollmin. erkennen, aber ich wäre trotzdem dafür, von vorne anzufangen.
(wohl hauptsächlich wegen der einfacheren Programmierung)
Scanzeiten:
Pit: anderes Programm (auf Highzählung umgerechnet) mein Vorschlag
<60ms = Störung <60ms = Störung
60-780ms = Fehler 782ms = Fehler 60-775ms = Fehler
780-860ms = 1 782-828ms = 1 775-825ms = 1
828-875ms = Fehler 825-875ms = Fehler
870-950ms = 0 875-922ms = 0 875-925ms = 0
960-1,78s = Fehler 922-1,17s = Fehler 925-940ms = Fehler
940-1,06s = Störung
1780-1,86s = Lastbit1? >1,17s = volle Minute 1,06-1,5s =
volle Minute
1870-1,95s = Lastbit0?
>1960 = Fehler >1,950 = Fehler
Lastbit müßte doch Firstbit heißen, denn in dieser Zeit fällt doch die
1. sek, an. Oder sehe ich da was falsch?
Bei den Zeiten bei voller Min. bin ich mir nicht so sicher, was da hin
kommen müßte. Ich denke nur, wenn die Minute voll ist, brauch man nicht
noch zusätzlich das erste Bit abfragen. Dann fängt es von vorne an. Die
Sollzeiten sollten in die Dokumentation, damit diese abhängig von der
Aufruffrequenz in das Programm eingerechnet werden können. Sonst würden
mehrfache Rundungsfehler entstehen, wenn jeder seine gerundeten Werte
weitergibt.
Die Scantabelle könnte in dieser Reihenfolge und mit BRLO abgefragt
werden. Dann wäre das etwas übersichtlicher. Und bei Fehler immer an
dieselbe Stelle springen. Der letzte Fehler benötigt einen gesonderten
Einsprung, weil das Gültigkeitsbit der vollen Minute zurückgesetzt
werden muß.
Die ersten 16 bits sollten noch gespeichert werden, damit diese später
für eine Wetterauswertung verwendet werden können.
mfg
PS: Meine Invertierungsergänzung habe ich wieder rausgenommen.
Hallo Wolfram, besten Dank für die tiefgründige Analyse, die erste ihrer Art. Wenn ich auch vorerst wenig Zeit finde, das Programm, das in dieser Form zufriedenstellend seit Monaten arbeitet weiter zu verbessern möchte ich zu Deinen Anregungen nur kurz folgendes sagen: Es war Ziel der Entwicklung, einen von weiteren Abhängigkeiten frei verwendbaren Baustein zu entwickeln. Diese Modularität bedeutet insbesondere, auf eine möglicherweise effizientere Zweiteilung in Mainprog+Interrupt zu verzichten. Die "verhältnismässig lange" Sperrzeit des Interrupts wird dadurch relativiert, daß dieser ja nur "alle Ewigkeit" von 0,8 Sek tatsächlich so "lange" ausgeführt wird und sonst nur ein Counter für die Pausenzeit inkrementiert wird. Weitere Verbesserungen stelle doch bitte in fertigem Code vor, wobei die aktuellen 99 Worte Platzbedarf bitte nicht überboten werden- denn minimalster Code war ein weiteres meiner Ziele... Gruß Pit
leider muß die längste Sperrzeit berücksichtigt werden, auch wenn sie nur 1x alle paar Jahre auftritt. In diesem Falle können dann Fehler entstehen. Meine Heizung hat ca. 10 Jahre einwandfrei funktioniert und aufgrund eines zeitl. orientierten Programmfehlers (Interrupt), ist meine Heizung im Wert von ca. 6000,- Euro kaputtgegangen. Darum lege ich jetzt wert auf fehlerfreie Programme, die sich nicht gegenseitig stören. Darum diese Aufteilung. Wenig Speicher ist richtig, aber das zeigt doch, daß auch andere Programme im AVR drin sein können. Ich werd sehen, was ich machen kann. Aber da muß ich wohl das Programm noch weiter analysieren. mfg
Die Bedenken bezüglich der Sperrzeit sind sicher absolut berechtigt, solange diese unkalkulierbar fürs System ist. Bisher habe ich aber keine Veranlassung, an der Stabilität und Zeitbedarf des Codes zu zweifeln. Was dagegen spricht, globale interrupts bereits zu Beginn der Datenauswertung wieder freizugeben habe ich noch nicht untersucht. Denn diese Auswertung ist nicht zeitkritisch. Vielleicht noch etwas zum Background dieses Programms. Es findet Verwendung als Teil einer Haussteuerung in 100% Assembler, die sehr viele Aufgaben zu erledigen hat. Die Idee war, alle "Betriebssystem"- Funktionen und insbesondere alle zeitkritischen Teile wie diese Funkuhr in einen (5 mSek) Timerinterrupt auszulagern. Das Hauptprogramm kann dann schalten und walten wie es will, solange es selbst keine Ansprüche auf Unterbrechungsfreiheit stellt. Als Programmierer ist man stets versucht, hunderttausend Abhängigkeiten zu kreieren- nur würde dann der Überblick über ein solches System sehr schnell verloren gehen. Deshalb die strikte Bausteinarchitektur.Und alles in allem funktioniert die Sache auch hervorragend, wenn konsequent umgesetzt. Die mit Wetterdaten gepickten Bits würd ich auch gerne verwenden, wenn nur der Code endlich offengelegt wäre :-)) Pit
Jep dazu bin ich auch übergegangen! Interupts sollten generell imemr alles so belassen wie es vorher war, und ihre Rückgaben nur über Flags oder eine Speicherzelle im SRAM regeln. Funktionen programmier ich inzischen auch so, das die Variablen über den Stack übergeben werden, und ich keine spezifischen Registernamen verwende. So wird selbst ASM Code in weiten Teilen "portabel" und die 10 Takte mehr tun meistens keinem weh :)
ich habe das Ganze jetzt in eine bessere Reihenfolge bzw. Ordnung gebracht. Es ist schon schwer, da durchzusteigen. Manchmal dachte ich, wie kann das nur funktionieren, aber dann habe ichs doch gefunden. Nachdem ich das jetzt weitgehend fertig habe, ist mir z.B. aufgefallen, daß das Datum Parity nicht geprüft wird. Gespeichert wird es, nur der Vergleich fehlt. Es besagt daher wohl nichts, wenn ein Programm läuft, daß das auch fehlerfrei wäre. Ich muß noch die Wetterdaten speichern. mfg
@Wolfram: Dann war wohl die lange Tüftelei doch noch nicht perfekt :-( Danke für den Hinweis auf die fehlende Prüfung der Datum Parity. Ich werd der Sache nun auch noch mal auf den Grund gehen müssen. Vielleicht könntest Du an dieser Stelle noch mitteilen, was Dir darüber hinaus "aufgefallen" ist. Und den verbesserten Code natürlich :-) Pit
@Wolfram: Beim Datum Parity liegst Du nun offensichtlich doch daneben. Bitte betrachte nochmal den Abschnitt ab dcf77_10, der nach Registrierung des letzten Bits der DCF77-Zeitscheibe, eben nämlich der Datum Parity aufgerufen wird: R21 enthält neben dem allgemeinen Fehlerflag auf Bit7 die Anzahl aller Einsen des Datum inklusive der Parity. Ein andi mit $81 gibt nun einen Fehler, wenn deren Anzahl ungerade wäre- das letzte Paritybit findet demnach durchaus Beachtung! Als interessante Frage bleibt natürlich, ob die Prüfung die Parität, der Impulslängen und Bitvollständigkeit allein zur 100%igen Fehlervermeidung ausreicht. Nach einigen Bedenken auch hier im Forum bin ich inzwischen dazu übergegangen, die empfangene Zeit erst nach dem zweiten erfolgreichen Empfang hintereinander zu übernehmen. Pit
anbei der neue Code. Das war gerade das, was ich nicht so schön fand, daß die Parity Prüfung z.B. an verschiedenen Stellen stattfindet. Deshalb hatte ich das übersehen. Der neue Code ist nicht getestet, weil ich noch keinen passenden Empfänger habe. Wäre schön, wenn das mal getestet werden könnte, ob da noch Fehler drin sind. Die Bausteinfunktion habe ich hier noch beibehalten. Aber anhand der Flags ist dann auch eine leichtere Auslagerung möglich. mfg
Ist R21 jetzt nicht doppelt belegt? Ansonsten schaut das zum Preis einiger zusätzlicher Codeworte sicher nicht schlecht aus - im Hinblick auf mehr Flexibilität und die Bereitstellung der "Wetterbits". Pit
ja, das eine Register ist doppelt belegt, weil es zu dem Zeitpunkt von der vorherigen Belegung nicht mehr gebraucht wird. Es wird dadurch ein Register eingespart. mfg
hat noch keiner das Programm testen können? Von den 35 Downloads sollte doch einer dabei sein, der einen DCF77 Empfänger angeschlossen hat. mfg
hallo Pit, nach meiner Meinung ist in Deinem und meinem Programm ein kleiner Fehler. Es wird zuerst die INIT aufgerufen. Darin wird das Reg. 23 verwendet, ohne das vorher die 0 in das Reg. geschrieben wird. Möglicherweise funktioniert das Programm deshalb, weil im zunächst fehlerhaften Verlauf die Reg. richtig gesetzt werden. Dadurch verzögert sich aber die erste gültige Anzeige. Alles nur theoretisch. mfg
Hallo Wolfram, wieso? Hast Du das "clr r23" übersehen? Der Aufruf der Init geschieht vorab vom Hauptprogramm aus. In meiner Anwendung brauche ich das allerdings gar nicht, weil das RAM bereits vorher komplett aus dem EEPROM initialisiert wird. Gruß Pit
hallo Pit, ich hatte noch die ältere Version in Bearbeitung und da fehlte das clr R23. Ich werde jetzt noch mal die beiden Versionen vergleichen. Mein Programm oben hat noch einige Fehler und wird wohl deshalb nicht laufen. Ich habe jetzt auch eine Aufteilung gemacht zwischen Interrupt und Main. Da werden das schon etwas mehr Words. Aber eine kurze Interruptlaufzeit erscheint mir wichtiger. Bin noch am Überlegen, ob man die lange Latte der Abfragen besser machen kann. mfg
Also wenn die (komplexere) Aufteilung zwischen Interrupt und Main noch umfangreicher ausfällt wär's vielleicht doch besser, man stellt die "Schönheit" hintenan. Ist es nicht letztlich egal, wo die eigentliche Programmfunktionalität nun verpackt wird? Natürlich immer vorausgesetzt, im Interrupt wird nicht sinnlos Zeit etwa in Pollschleifen vertrödelt und ein SEI macht schnellstmöglich Platz für ggf. wichtigere Dinge, die in der Interrupttabelle prioritätsmäßig dann weiter oben zu stehen haben. Die Abfragenliste finde ich auch nicht unbedingt "schön", sie war aber immer die einfachste aller Varianten. Bin gespannt wie das noch kürzer gehen könnte! Denn den Code weiter einzudampfen wäre durchaus noch eine Anstrengung wert. Im Auge hätte ich da insbesondere den Verzicht auf den Test der Paritätsbits. Die Prüfung a) der Bitvollständigkeit, b) der korrekten Bittimings und c) der Plausibilität durch Zeitvergleich mit der vorhergehenden Minute reicht meiner Meinung nach "in der Praxis" 100%ig zur Vermeidung von Fehlern und käme mit noch weniger Code aus. Zugegeben: mehr als sportlicher Ehrgeiz ist das aber nicht :-)) Pit
diese Aufteilung halte ich schon für notwendig. Habe da auch eine gute Schnittstelle gefunden. Jede Verzögerung im Interrupt kann andere Aufgaben behindern. Ein SEI im Interrupt geht auch nicht, weil dann nicht nur die vorhergesehene Aufgabe abgearbeitet wird, sondern auch andere weniger wichtige, weil das eben ein Pauschalinterrupt ist. Meine Abfragenliste habe ich um 6 Bytes kürzer bekommen, hatte gedacht, daß die Auswikungen besser sind. Und eine etwas längere Ausführungszeit. Diese spielt hier aber nicht so die Rolle, weil diese in der Main liegt und ich dafür für alles zusammen 1 sek. Zeit habe. Daß weniger Prüfungen und Kontrollen auch weniger Code haben, ist klar. Aber das sollte nicht das Ziel sein. Im Gegenteil, vom Prinzip her sollte man es sich angewöhnen, möglichst viele Kontrollen zu machen. Ich spare mir aber oft den Code, der eine möglichst genaue Fehleranalyse ausgibt. Darum wird bei mir nach einem Fehler nur Init und zum Ende gesprungen. dcf77__0a: ldi zl,low (state*2) ldi zh,high(state*2) nextstate: lpm temp,z+ cp r22,temp brlo dcf77_8 ; Zyklus brne nextstate adiw z,8 lpm temp,z ldd ZL ,Y+13 ;DCF77TAL ldd ZH ,Y+14 ;DCF77TAH ;Z-> NEWTIME ARRAY cpi temp,7 breq dcf77_7 ; LastBit rjmp dcf77_9 ; Prüfbit State: .db 8,16,$15,$1c,$23,$29,$2c,$31,$3a,7,7,7,9,9,7,7,7,9 ich weiß jetzt nicht, ob ein fehlender Minutenimpuls ausreichend abgesichert ist. mfg
Hallo Pit Ist zwar schon ne ganze Weile her, als du den Assemblerbaustein hier ins mikrokontrolle.net reingestellt hast, aber ich komm mit meinem Projekt nicht wikklich voran. Ich versuche gerade deine DCF77-dekodier-Routine in meinem Studio-Uhr Projekt zu integrieren. Hast du eventuell noch mehr Unterlagen (Registeraufbau im RAM, Aufbau von DCF77CHECK..) Ich muss meine interne Uhr mit der dcf Zeit syncronisieren. Leider komm ich nicht mal zu einer Statusauswertung, ob ein Fehler vorliegt und vor allem wann bekommt die Routine mit, dass eine neue Übertragung beginnt? Also wann sind 58 Impulse gesendet worden (denn der 59 müsste ja eigentlich fehlen). Denn genau da könnt ich meine Syncronisation starten. @ Peter Danneger Ich hatte erst die Routine von Peter Dannegger ausprobiert und auf den mega8 angepasst, doch da hab ich nur 32:00 (hh:mm) nach der Syncronisation angezeigt bekommen. Wenn dann mal das DCF-Paket verworfen wurde, zählte die interne Uhr einfach wie gewollt weiter. Allerdings kam es nun zu einer erneuten gültigen Synchronisation, zeigte die Anzeige wieder 32:00 an. Ich verstehe hier auch nicht so recht, woher die NewSecond, NewMinute, NewHour... u.s.w. her kommen. Vieleicht kann mir das ja der Peter noch sagen, denn darauf wird ja die Zeit syncroniesiert. In der Hoffnung hier diesen Treed mal wieder etwas Leben einzuhauchen.. Grüße der Steffen
@ Peter Dannegger Ich hab es gefunden... Beim ATtiny12 existiert ja gar kein RAM. Im ATmega8 sind die Register-Adressen im RAM gemapped. Das heißt: Es wurde immer irgend eine wilde Speicherstelle geladen anstatt die des Registers r10, r11,..,r15 ! Das lag hauptsächlich am Pointerregister Xh. Das hatte immer eine 0x04 drin stehen. (woher auch immer) Das darf es aber beim ATmega8 nicht, denn die 32 Arbeitsregister sind ab $0000->r0, $0001->r1,.., $001A->r10,..., u.s.w organisiert. Hab das in deinem Code mal geändert. Ist wahrscheinlich auch nur wegen dem portieren in einen ATmega8 wichtig. Kenn den ATtiny12 nicht so gut. Nun läuft die DCF77 syncronisation super! ..wenn dann mal das Signal stark genug ist und ich nicht so oft einen Error detektiere. Änderung ist im Anhang! Steffen
Hi Pit, DANKE!!!!!! Man muss sich schon des Gehirn verrenken um das zu verstehen. (DCF77CHECK Doppelnutzug) :) Habs mit einer Soft-RTC versehen und läuft ... und läuft ... ganz großes DANKE! Z8
Hallo, ich habe den Code von Pit gerade in mein Projekt eingefügt, funktioniert soweit auch tadellos. Jedoch werden in den Speicheradressen wie STU, MIN usw keine Zeiten abgelegt. Das ablegen sollte doch in diesem Programunkt ablaufen oder??? dcf77_12: std Z+11,r21 ;nach MIN...JHR sichern ld r21,-Z dec r20 brne dcf77_12 std Z+11,r20 ;Sek. = 0 setzen std Z+10,r20 ;1/100 Sek. = 0 setzen Kann mir hier vlt jemand weiterhelfen da ich mich erst in den SRAM einarbeite. Gruß HAllo P.S: Controller ist ein ATmega8
Hallo schrieb: > Das ablegen sollte doch in diesem Programunkt > ablaufen oder??? Ja, aber nur bei erfolgreichem Empfang! Am besten mit ner kleinen LED den Puls kontrollieren- da darf kein Flackern dabei sein. Gruß Jan K.
Hallo Pit, Dein AVR-ASM Sorcecode habe ich auf Anhieb zum Laufen gebracht. Doch ab und zu bekomme ich eine falsche Uhrzeit angezeigt: z.B. 17:84:21 Deßhalb bin ich auch dazu übergegangen, die empfangene Zeit erst nach dem zweiten erfolgreichen Empfang hintereinander zu übernehmen. Dadurch entsteht aber ein neues Problem: Die Sommer-/Winterzeit Umschaltung erfolgt mit einer Minute Verspätung! Datum und Wochentag rechne ich hoch. Ich wollte noch das DCF77 Bit 16 Abspeichern um es abfragen zu können, hab´s aber nicht hinbekommmen! NEWTIME: .BYTE 7 ;Minute, Stunde, Kalendertag, Wochentag, Monat, Jahr, DST Vielleicht kannst Du mir ja einen Tip geben. Gruß Franz
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.