Forum: Projekte & Code DCF77 AVR-Assemblerbaustein


von Pit (Gast)


Angehängte Dateien:

Lesenswert?

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

von Pit (Gast)


Angehängte Dateien:

Lesenswert?

Achtung! Initialisierungsroutine enthielt noch einen kleinen Fehler
(hatte ich selbst nicht vorab verwendet). Jetzt dürfte es aber passen.

Pit

von Läubi (Gast)


Lesenswert?

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 :)

von Läubi (Gast)


Lesenswert?

Ach ja ein Tiny+das DCF Modul von Reichelt solte doch dafür geeigent
sein oder wird irgenwelche Spezillen eigenschaften beim AVR benötigt?

von Joachim B. (joachimb)


Angehängte Dateien:

Lesenswert?

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

von Christoph Kessler (Gast)


Lesenswert?

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.

von Joachim B. (joachimb)


Lesenswert?

danke für den Hinweis,
das war mir neu.

von Pit (Gast)


Lesenswert?

@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

von peter dannegger (Gast)


Lesenswert?

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

von Läubi (Gast)


Lesenswert?

< 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 ;)

von Pit (Gast)


Lesenswert?

@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

von peter dannegger (Gast)


Lesenswert?

@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

von Pit (Gast)


Lesenswert?

@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

von Pit (Gast)


Angehängte Dateien:

Lesenswert?

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

von Winne (Gast)


Lesenswert?

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

von Jens D. (Gast)


Lesenswert?

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..

von Joachim B. (joachimb)


Lesenswert?

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

von Joachim B. (joachimb)


Lesenswert?

Nachtrag:
Die Polung (normal bzw. invertiert) des DCF-Signals ist unerheblich.
Der Dekoder stellt das fest.

von petersch (Gast)


Lesenswert?

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

von Uwe (Gast)


Lesenswert?

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

von Joachim B. (joachimb)


Lesenswert?

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

von petersch (Gast)


Lesenswert?

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

von Wolfgang Horn (Gast)


Lesenswert?

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

von Uwe (Gast)


Lesenswert?

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

von Raik (Gast)


Angehängte Dateien:

Lesenswert?

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

von Ralf D. (Gast)


Lesenswert?

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 ?

von Raik (Gast)


Lesenswert?

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

von Ralf D. (Gast)


Lesenswert?

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

von Raik (Gast)


Angehängte Dateien:

Lesenswert?

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

von Ulli (Gast)


Angehängte Dateien:

Lesenswert?

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

von Ulli (Gast)


Lesenswert?

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 :-)

von Robert Sommerfeld (Gast)


Lesenswert?

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

von Michi (Gast)


Lesenswert?

@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

von Raik (Gast)


Lesenswert?

@ 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

von Wolfram Q. (quehl)


Lesenswert?

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

von Pit (Gast)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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.

von Pit (Gast)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Pit (Gast)


Lesenswert?

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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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 :)

von Wolfram Q. (quehl)


Lesenswert?

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

von Pit (Gast)


Lesenswert?

@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

von Pit (Gast)


Lesenswert?

@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

von Wolfram Q. (quehl)


Angehängte Dateien:

Lesenswert?

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

von Pit (Gast)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Pit (Gast)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Pit (Gast)


Lesenswert?

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

von Wolfram Q. (quehl)


Lesenswert?

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

von Steffen (Gast)


Lesenswert?

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

von Steffen (Gast)


Angehängte Dateien:

Lesenswert?

@ 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

von Z8 (Gast)


Lesenswert?

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

von Hallo (Gast)


Lesenswert?

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

von Jan K. (pit1)


Lesenswert?

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.

von Franz Bandorf (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.