PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Zeit mit DCF-Modul auslesen (brauche noch Hilfe!!!!!!!!!!!!)



BurningWave
09.08.2008, 12:51
Hallo,

ich habe einen Code geschrieben, der die Zeit mit einem DCF-Modul auslesen soll. Dieses Modul kommt in einer Alarmanlage zum Einsatz. Die Alarmanlage funktioniert aber nicht wirklich so, wie sie soll. Ich vermute, dass sie irgendwo beim auslesen der Zeit hängen bleibt. Jetzt wollte ich euch mal fragen, ob ihr in meinem Code noch irgendwelche Fehler findet.

Danke
_R2D2

SprinterSB
09.08.2008, 15:17
http://www.google.de/search?hl=de&q=volatile+C&btnG=Suche

Dirk
10.08.2008, 10:09
... wollte ich euch mal fragen, ob ihr in meinem Code noch irgendwelche Fehler findet.
Wo ist denn DEIN Code?

Gruß Dirk

BurningWave
10.08.2008, 12:08
@Dirk
dcf77.h - als Anhang zum download

McJenso
10.08.2008, 15:01
Hallo,

es fehlt die int main().


Im Ernst, Fehlerbeschreibung, Controllertype, minimales compilierfähiges Programm fehlen.

Ich vermute, dass sie irgendwo beim auslesen der Zeit hängen bleibt.
Worauf stützt sich deine Vermutung.
Wonach soll ich suchen? Weiß der Fuchs, was du noch alles mit der Variable wert anstellst, nur mal als Beispiel.
Ich möchte dir gerne bei deinem Problem helfen, kann es so aber nicht.

Gruß

Jens

sternst
10.08.2008, 15:40
Der Fehler wurde von SprinterSB doch schon längst benannt, wenn auch etwas ungewöhnlich und knapp.

Die Funktion GetTime bleibt hier hängen:

while(!fertig)
{}
weil fertig nicht als volatile deklariert ist.

Nach der Korrektur dieses Fehlers wird GetTime aber vermutlich immer noch nicht richtig funktionieren, weil auch Fehler volatile sein muss.
(Und vielleicht noch weitere Variablen, denn so genau habe ich es mir nicht angesehen)

Davon abgesehen springt mir noch eine andere Sache ins Auge:

TIFR |= (0 << ICF1) | (0 << TOV1);
TIMSK |= (0 << TICIE1) | (0 << TOIE1);
Diese beiden Zeilen sind NOPs, die tun rein gar nichts, schon gar nicht halten sie den Timer an.

Und auch in den Blöcken dieser Form:

Zeit.Stunde =
ZeitBits[28]*1+
ZeitBits[29]*2+
ZeitBits[30]*4+
ZeitBits[31]*8+
ZeitBits[32]*10+
ZeitBits[33]*20;
steckt ein kapitaler Denkfehler.

McJenso
10.08.2008, 16:19
Hallo,

ein fehlendes volatile ist sicher ein Fehler. Führt aber nicht zwingend sondern nur möglich zu einer Fehlfunktion. Die weiteren, von dir aufgeführten Sachen, habe ich mir schon nicht mehr angeschaut. Mein erster Verdacht liegt in den großen Variablentypen und der Verwendung in der ISR bei leichtfertigem Zugriff außerhalb dieser. :mrgreen:

Ist aber alles Spekulation.

Gruß

Jens

sternst
10.08.2008, 16:33
Stimmt, nicht zwingend, aber beim GCC mit eingeschalteter Optimierung liegt die Wahrscheinlichkeit, dass "while(!fertig) {}" zu einer Endlosschleife wird, sehr nahe an 100 %. ;-)

BurningWave
13.08.2008, 18:34
Davon abgesehen springt mir noch eine andere Sache ins Auge:


TIFR |= (0 << ICF1) | (0 << TOV1);
TIMSK |= (0 << TICIE1) | (0 << TOIE1);


Diese beiden Zeilen sind NOPs, die tun rein gar nichts, schon gar nicht halten sie den Timer an.

Stimmt, man kann ja mit OR keine 1 löschen.


TIMSK ^= (1 << TICIE1);
TIMSK ^= (1 << TOIE1);

So müsste sich der Timer doch beenden lassen.



Und auch in den Blöcken dieser Form:


Zeit.Stunde =
ZeitBits[28]*1+
ZeitBits[29]*2+
ZeitBits[30]*4+
ZeitBits[31]*8+
ZeitBits[32]*10+
ZeitBits[33]*20;


steckt ein kapitaler Denkfehler.

Was stimmt den daran nicht? Ich habe mir es so gedacht:
Wenn das Bit an der entsprechenden Position 1 ist, so wird das Produkt 1*X zu Zeit.Stunde addiert.

Danke für eure Hilfe
mfg _R2D2

sternst
13.08.2008, 22:27
So müsste sich der Timer doch beenden lassen.
Ja, wenn beide Bits ganz sicher vorher 1 sind. Sicherer wäre ein auf Null setzen, das nicht vom aktuellen Zustand abhängt:
TIMSK &= ~((1<<TICIE1) | (1<<TOIE1));


Wenn das Bit an der entsprechenden Position 1 ist, so wird das Produkt 1*X zu Zeit.Stunde addiert.
Und welche Wertigkeiten (X) haben die Bits an Position 4 und 5? (Tipp: 10 und 20 sind es jedenfalls nicht)

fhs
14.08.2008, 09:56
Hallo,


... welche Wertigkeiten (X) haben die Bits an Position 4 und 5? (Tipp: 10 und 20 sind es jedenfalls nicht)
sowohl die Minuten- als auch die Stundencodierung ist BCD (4 Bit für die Einer- und 2 Bit für die Zehnerstelle, obwohl das eine Verschwendung darstellt...); die Wertigkeiten "10" und "20" sind deshalb schon korrekt.

Gruß

Fred

sternst
14.08.2008, 13:15
Ups, dass das BCD kodiert sein könnte, habe ich nicht bedacht.

Daher von mir ein großes zu Kreuze kriechendes SORRY!

BurningWave
14.08.2008, 16:29
Eins habe ich jetzt immer noch nicht verstanden: Wann wendet man "volatile" an?

mfg

fhs
14.08.2008, 16:48
Hi,


...Wann wendet man "volatile" an?
Beim Programmieren von "embededed systems" wird grundsätzlich "volatile" eingesetzt,
1. wenn eine Variable in einer ISR und gleichzeitig in einem anderen Programmteil vorkommt,
2. beim Datenaustausch zwischen mehreren Threads und
2. wenn man auf ein "memory mapped" peripheres Register zugreift.

Dies ist alles mit Beispielen hier (http://www.netrino.com/node/80) erklärt.

MfG

Fred

BurningWave
26.08.2008, 19:42
Ich hatte jetzt Zeit, alles noch mal genau zu testen und dabei ist mir aufgefallen, dass der µC nach dem Aufruf von GetTime nach ca. 14 Sekunden einen Reset macht. Nach diesem Reset fängt das Programm wieder von vorne an, die Variablen werden aber komischerweise nicht gelöscht. Wenn nach dem ersten Reset ein Timer gestartet wird macht der Controller wieder diesen komischen Reset. Ich denke, dass irgendetwas mit der Timersteuerung im Programm nicht stimmt.
Am µC kann es nicht liegen, da es weder mit einem AtMega8, noch mit einem AtMega32 funktioniert.

Stimmt diese Zeile oder kann man den Wert so nicht umrechnen?


wert = (ICR1L | (ICR1H << 8)) * (TAKT / (256UL * 65535UL) / 1000UL); //gezählter Wert in ms umrechnen (Takt=3,6864MHz)


Ich habe langsam das Gefühl, dass der AVR-gcc Compiller mit sehr großen Programmen nicht zurecht kommt. Weiß jemand, wo ich die neueste Version finde (Ich habe schon danach gegoogelt, finde aber nichts)?

mfg

BurningWave
27.08.2008, 17:41
Ich bin schön dumm: Suche ewig lang alles nach diesem Fehler ab, dabei habe ich in dieser Zeile


SIGNAL(SIG_OVERFLOW1)

"SIG_" vergessen. Jetzt macht der µC keinen Reset mehr, aber die Zeit kann ich auch nicht empfangen. Entweder igrendetwas im Programm stimmt nicht, oder das Modul empfängt nichts. Was muss man beachten, um überhaupt ein Signal zu bekommen?

mfg

Hubert.G
27.08.2008, 18:14
Hast du schon mal eine LED über einen Transistor an den Ausgang des Moduls gehängt. Noch besser wenn du dir einen Ausgang programmierst an den du eine LED hängst, die dir die Eingangsimpulse anzeigt. Die Impulse müssen schön gleichmässig kommen. Den Minutenwechsel kann man durch die größere Pause erkennen.
Das Modul mit Antenne sollte schon min. 20cm von µC und LCD entfernt sein.
Die Ausrichtung zum Sender sollte auch stimmen.

BurningWave
27.08.2008, 21:40
Das Modul funktioniert, ich habe eine LED an den DATA Ausgang gehängt und diese wird regelmäßsig heller und dunkler. Also muss der Fehler im Programm sein.

Hubert.G
27.08.2008, 21:53
Setz dir trotzdem auf einen freien Ausgang deines Kontroller eine LED, diesen Ausgang kannst du dann Schritt für Schritt in dein Programm einbauen und so kontrollieren wie weit es funktioniert.

sternst
27.08.2008, 22:18
Also muss der Fehler im Programm sein.

Wenn du den Fehler im Programm vermutest und dir von uns Hilfe bei der Fehlersuche erhoffst, wäre es dann nicht angebracht, mal die aktuelle Version des Sourcecode zu posten?

BurningWave
29.08.2008, 21:14
OK, hier ist mal die überarbeitete Version der Datei.

Ich habe jetzt doch ein kleines Programm geschrieben, das eine LED einschällt, wenn das Signal kommt. Dieses Programm funktioniert auch. Die LED blinkt ziemlich gleichmäßig.

Ich habe das Gefühl, dass der Timer1 ein bisschen zu schnell zählt, da der Overflow-Interrupt ziemlich schnell hinter einander erfolgt. Mein Verdacht liegt immer noch in dieser Zeile (obwohl ich es mit dem Taschenrechner nachgerechnet habe und der Timer erst alle 14,4 Sekunden überlaufen dürfte):


wert = (ICR1 * (TAKT / (256UL * 65535UL) / 1000UL)); //gezählter Wert in ms umrechnen (Takt=3,6864MHz)


mfg

sternst
29.08.2008, 22:19
der Timer erst alle 14,4 Sekunden überlaufen dürfte

Poste mal, wie du das ausrechnest.
Bei 3,6864 MHz und einem Teiler von 256 komme ich auf einen Overflow alle 4,55 Sekunden.


wert = (ICR1 * (TAKT / (256UL * 65535UL) / 1000UL)); //gezählter Wert in ms umrechnen

Was hat das 65536 darin zu suchen? Wenn du eine bestimmte Anzahl Zählertakte in die äquivalente Zeit umrechnen willst, welche Rolle spielt dann, nach wie viel Takten der Zähler überläuft? Ein Takt ist immer gleich lang, egal ob der Zähler nun bei 65535 überläuft, oder niemals. Und auch die Tatsache, dass TAKT im Zähler steht, zeigt, dass die Formel falsch sein muss, denn t = 1 / f

sternst
29.08.2008, 22:51
SIGNAL(SIG_INPUT_CAPTURE1)
{//wird bei steigender Flanke des Signals ausgelöst um die Dauer der Pause zu berechnen

...

TCCR1B |= (1 << ICNC1) | (1 << CS12); //Störunterdrückung ein; fallende Flanke; Taktteiler: 256

Was denn nun, steigende Flanke oder fallende?

Ich habe zwar den Code noch nicht so detailliert analysiert, um dir sagen zu können, was du da genau per Input Capture misst, aber die "Pause" ist es sicher nicht.


if((wert>875) && (wert<925))
{
...
}
if((wert>775) && (wert<825))
{
...
}
else
{//keine Übereinstimmung der Pausendauer -> An aktueller Position Fehlermarke (-1) setzen

Das passt auch nicht, denn wenn wert zwischen 875 und 925 liegt, landest du nicht nur im ersten if, sondern zusätzlich auch im else-Zweig.

BurningWave
30.08.2008, 22:48
Poste mal, wie du das ausrechnest.
Bei 3,6864 MHz und einem Teiler von 256 komme ich auf einen Overflow alle 4,55 Sekunden.

Stimmt, das habe ich vorher auch bemekt. Aber die Funktion SetTime() liefert bei mir schon nach ca. 6 Sekunden false zurück. Das heist ja, dass der Timer viel zu schnell zählt?!

Wie ich genau auf diese Formel gekommen bin, weiß ich auch nicht mehr. In meinem µC-Buch ist die Berechnung solcher Dinge auch nicht gut erklärt (das Buch ist sicher nicht das beste). Wie würde die Formel richtig lauten?

mfg

BurningWave
31.08.2008, 20:06
wert=ICR1/14;

Wenn man die Zeile so umändert, müsste es doch funktionieren, da der Wert 65535 in ICR1 4,55sec entspricht. Dann entspricht der Wert 14 1ms.

Aber es funktioniert immer noch nicht...

mfg

Edit: Ich habe gar nicht bemekt, dass der Thread schon 2 Seiten hat, deswegen habe ich die letzten Beiträge nicht gefunden. :wink:

Aber das mit der Messung der Pausen müsste schon stimmen, da der Interrupt am Ende der Messung, eben bei einer steigenden Flanke ausgelöst wird. Das Bit ICES1 in TCCR1B ist deshalb nicht gesetzt, damit die Messung bei einer fallenden Flanke gestartet wird.

Dirk
31.08.2008, 21:36
Hallo _R2D2,

... das mit der Messung der Pausen müsste schon stimmen, da der
Interrupt am Ende der Messung, eben bei einer steigenden Flanke ausgelöst wird.
Im Prinzip ist es egal, auf welche Flanke man reagiert. In einem meiner DCF-Decoder habe ich auf jede Flanke reagiert und die Zeit zwischen den Flanken gemessen. Wenn das 100 oder 200 ms waren, dann hatte ich die Impulse selbst, bei Werten von 800/900/1800/1900 ms waren es die Pausen. Die braucht man dann für die Decodierung.

Gruß Dirk

sternst
31.08.2008, 21:49
Dann entspricht der Wert 14 1ms.

Kommt ungefähr hin.



Aber es funktioniert immer noch nicht...

Unter anderem deswegen, weil in ICR1 einfach nicht das drin steht, was du vermutest. (*1)


Aber das mit der Messung der Pausen müsste schon stimmen, da der Interrupt am Ende der Messung, eben bei einer steigenden Flanke ausgelöst wird. Das Bit ICES1 in TCCR1B ist deshalb nicht gesetzt, damit die Messung bei einer fallenden Flanke gestartet wird.

Wenn du ICES1 auf "fallende Flanke" konfigurierst, wieso glaubst du dann, der Interrupt würde bei der steigende Flanke ausgelöst? (*2)


*1+2: Da ist wohl noch mal ein genaues Studium des Input-Capture-Kapitels im Datenblatt nötig.

BurningWave
02.09.2008, 20:23
Ich habe das Programm jetzt noch einmal überarbeitet. Das mit den Flanken stimmt jetzt. Das Programm schällt jetzt noch eine LED an und aus, wenn das Signal kommt, bzw. nicht kommt. Die LED blinkt auch regelmäßig. Aber die einzelnen Bits kann ich immer noch nicht auslesen...

Ich finde trotz gründlichem Überprüfen einfach keinen Fehler mehr. :(

mfg

Hubert.G
02.09.2008, 20:44
Setz dir einmal eine Led dort in dein Programm wo du den Start erkennst.
Wo schaltest du zwischen fallender und steigender Flanke um?
Es fehlt mir die main() und warum schreibst du das in die dcf77.h und nicht in dcf77.c

BurningWave
04.09.2008, 14:10
Wo schaltest du zwischen fallender und steigender Flanke um?

Was meinst du damit? Wo soll denn ich umschalten?

In main() wird was das dcf-Modul betrifft nur als erstes dcf_init() und dann SetTime() aufgerufen.

mfg

sternst
04.09.2008, 15:09
Was meinst du damit? Wo soll denn ich umschalten?

Wenn du die Zeit zwischen zwei gleichen Flanken misst (egal ob steigende oder fallende), wie willst du dann entscheiden, ob es eine 0 oder 1 war?

PS: Das würde zwar auch gehen, aber man müsste dann auch den Zustand des vorigen Bits mit in die Entscheidung einbeziehen.

Hubert.G
04.09.2008, 15:43
Ich habe mal so eine Erkennung gebastelt, da habe ich auf die fallede Flanke gewartet, dann den Timer gestartet, auf steigende Flanke umgeschalten, bei erkennen den Timer gestoppt, ausgelesen und wieder auf fallende Flanke umgestellt für das nächste Bit.


In main() wird was das dcf-Modul betrifft nur als erstes dcf_init() und dann SetTime() aufgerufen.
Das erklärt nicht warum du den Code in die dcf.h und nicht dcf.c schreibst.

BurningWave
05.09.2008, 19:49
Das erklärt nicht warum du den Code in die dcf.h und nicht dcf.c schreibst.

Das mache ich schon lange so, weil ich keine zwei Dateien (dcf77.h und dcf77.c) haben möchte. In .c-Dateien kommen bei mir nur die Hauptprogramme und die dazugehörigen Unterprogrammen. Aber das ist doch für die Funktion des Programms egal.

Ich habe das Signal jetzt mal aufgezeichnet, und dabei ist mir aufgefallen, dass sehr viele kleine Störungen (meist direkt vor den eigentlichen Impulsen) auftreten. Dann ist es ja kein Wunder, dass das Auslesen der Zeit nicht funktioniert. Woran können diese Störungen liegen? An anderen Geräten, die in der Nähe sind und den Empfang stören könnten kann es nicht liegen, da ich es auch schon drausen auf dem Balkon probiert habe.
Ich invertiere und verstärke die Signale der DATA-Leitung sonst nur mit einem einfachen Transistor (BC 547C). (DATA an Basis; Pulldown an Basis (R mit 40kOhm); Kollektor an ICP1 (interner Pullup im µC ist aktiviert); Emitter an GND) Ist der Pulldown Widerstand möglicherweise zu groß?

Als Anhang habe ich die Aufzeichnung von einer Minute und von den ersten 10 Sekunden der Minute angehängt. Dort kann man die Störungen gut sehen.

mfg
_R2D2

Hubert.G
05.09.2008, 20:13
Wenn der Ausgang des DCF-Moduls Open-Collektor ist dann glaube ich nicht das deine Beschaltung richtig ist.
Siehe mal hier: www.mikrocontroller.net/articles/DCF77-Funkwecker_mit_AVR

BurningWave
06.09.2008, 21:23
Wenn der Ausgang des DCF-Moduls Open-Collektor ist dann glaube ich nicht das deine Beschaltung richtig ist.
Siehe mal hier: www.mikrocontroller.net/articles/DCF77-Funkwecker_mit_AVR

Doch, meine Beschaltung stimmt schon, da der µC die Impulse ja erkennt. Nur die Störungen stören eben das Empfangen.
Es haben aber noch andere das Problem mit den Störungen: http://www.mikrocontroller.net/topic/97295
bei genauerem Betrachten erkennt man nämlich an meinen Aufzeichnungen auch diesen Sägezahn bei den Flanken und diese Störimpulse, die vor dem eigentlichen Impulsen auftreten. Hat jemand eine Idee, wie ich den Eingang des µCs ohne großen Aufwand entsprechend entprellen kann (möglichst mit der Software, damit ich auf meine schon volle Platine nicht noch mehr Bauteile löten muss)?

mfg
_R2D2