Hallo! Ich wollte mal von denen, die sich schon mit DCF77 beschäftigt haben, wissen, wie ihr die Impulslängen des Signals messt. So in Stichworten... Gruß Chris
Falls du einen AVR benutzt, d nehme ich den ICP (Input-Capture-Pin), der hat 'ne 'Rauschunterdrückung' und eignet sich für solche Aufgaben hervorragend.
Mit nem Timerinterrupt, der alle 10ms nachschaut, ob sich der Pegel geändert hat und mitzählt: 8..12 = 100ms 18..22 = 200ms 90..110 = 1s 190..210 = 2s D.h. eine Byte-Zählvariable erschlägt alle interessierenden Zeiten. Einfacher gehts nicht. Peter
Christian S. wrote:
> undwie triggerst du den timer? mit nem externen Int.?
???
Der Timer läuft durch.
Den braucht man doch eh, für die interne Uhr bei Empfangsstörungen.
Peter
Doch natürlich! Ich hatte mir die ganze Messung nur komplett anders vorgestellt... Mein Versuch war: steigende Flanke -> timer starten, Fallende Flanke -> Timer stoppen -> Zeit auswerten Eure MEthode hört sich nur wesentlich einfacher an....
ICh habs nun mal so versucht.... aber irgendwie funzt das nciht :(
1 | #pragma vector=TIMERA0_VECTOR
|
2 | __interrupt void Timer_A0 (void) |
3 | {
|
4 | |
5 | if(P2IN & 0x01) |
6 | {
|
7 | timecount += 1; |
8 | }
|
9 | |
10 | //position(2,1);
|
11 | //int2string(timecount,buffer);
|
12 | //printtext(buffer);
|
13 | |
14 | if(timecount >= 8 && timecount <= 12) |
15 | {
|
16 | position(2,1); |
17 | printtext("0"); |
18 | timecount = 0; |
19 | }
|
20 | |
21 | if(timecount >= 18 && timecount <= 22) |
22 | {
|
23 | position(2,1); |
24 | printtext("1"); |
25 | timecount = 0; |
26 | }
|
27 | |
28 | CCR0 = 327; |
29 | }
|
In deiner Funktion wird timecount niemals den Wert 18 erreichen. Wenn timecount bis auf 8 hochgezählt hat, detektierst du eine 0 und das wars dann auch schon. Du sollst 1 Sekunde lang den Eingang alle 10 ms beobachten. Wenn er in dieser 1 Sekunde 8 bis 12 mal 1 war, dann gilt das als 0. Du musst also die Interrupts mitzählen. Dein Interrupt tritt alle 10 ms auf. Nach 100 Interrupts ist also 1 Sekunde vergangen. Beim Start einer Sekunde setzt du den timecount auf 0. Danach prüfst du bei jedem Interrupt den Zustand des Port-Pins und zählst gegebenenfalls den timecount hoch. Wenn der 100-ste Interrupt auftritt (also nach 1 Sekunde) schaust du nach wie oft du eine 1 vorgefunden hast (du wertest also den timecount aus). Anstatt 100 würde ich vielleicht auf 90 gehen. An der Anzahl in timecount ändert das nichts, aber du wirst wahrscheinlich noch etwas Zeit brauchen um dich auf die nächste 0-1 Flanke synchronisieren zu können.
Diese Art Impulse auszumessen frisst unnötigerweise Rechenleistung, da alle 10ms ein INT ausgeführt wird. Dann lieber fallende und steigende Flanke auswerten Zeit messen und mit Toleranz bewerten. Damit kann ich 1 und 0 festlegen. Alles was nicht 1 oder 0 ist muss ein Fehler sein, das heißt ich muss wieder von vorne anfangen die Bits zu zählen.
@Sonic: Das ist nicht so ganz richtig. Der Interrupt kommt zwar alle 10ms, kann aber extrem kurz gehalten werden. Die Auswertung der gemessenen Zeiten geschieht in der Main. So wie Du es mit dem ICP machst, hatte ich früher auch gearbeitet, bis ich feststellte, daß bei Störungen des DCF-Signals durch Maschinen oder Lampen der ICP bis zu 100 mal pro Sekunde wild getoggelt wurde. An "Messen" war da nicht mehr zu denken. Zudem verfälschten kleine Störimpulse immer wieder die Messung. Da reichte schon das Einschalten einer Leuchstoffröhre und schon war das ganze Zeitprotokoll im Eimer. Durch die 10ms-Timer Variante kann man all diese Probleme umgehen.
In Programmen dieser Art benötigt man sowieso eine Zeitbasis. Sei es für die Ausgabe auf gemultiplexten 7-Segmentanzeigen (ok, dann sind 10 ms nicht gerade viel) oder sei es um die Uhr auch dann am laufen zu halten, wenn das DCF Signal ausfällt. Ob diese Zeitbasis den DCF Eingang noch zusätzlich beobachtet, fällt dann nicht mehr wirklich ins Gewicht.
@TravelRec.:
Um Fehler sauber erkennen zu können (Einschaltimpulse von
Leuchtstofflampen sind welche) muss man den GANZEN Impuls messen, nicht
in 10ms-Abständen. Wenn ich in Kauf nehmen will, dass ich einen Fehler
nicht erkenne kann es halt passieren dass ein falsches Protokoll
'rauskommt. Der Noise-Canceller vom ICP leistet bei mir sehr gute
Dienste, habe so gut wie kein nicht vollständiges Protokoll.
>In Programmen dieser Art benötigt man sowieso eine Zeitbasis.
Stimmt. Die ist bei mir 1s (Timer1, RTC).
Ich will ja noch was Anderes machen als nur die Uhr laufen zu lassen, da
kann's mit der Rechenleistung schon mal knapp werden, bzw. für
Berechnungen etwas länger dauern.
>habe so gut wie kein nicht vollständiges Protokoll. Ich auch nicht! Der NoiseCanceller des ICP überbrückt gerade mal 4 CPU-Zyklen, für Störimpulse im oberen µs bis ms-Bereich absolut nonsense. >Um Fehler sauber erkennen zu können (Einschaltimpulse von >Leuchtstofflampen sind welche) muss man den GANZEN Impuls messen, nicht >in 10ms-Abständen. Ich messe den ganzen Impuls, im 10ms "Raster", nicht in 10ms "Abständen". Da die DCF-Signale 100 bzw. 200 ms lang sind, bekomme ich Zahlen von 8-12 für 100ms +-Toleranz und 18-22 für 200ms +-Toleranz. Ich will nicht Fehler erkennen, sondern DCF-Impulse. Die Fehlererkennung findet über die Prüfbits im DCF-Protokoll statt. Störimpulse an sich haben durch diesen programmtechnischen "Tiefpass" so gut wie keine Chance, es sei denn, der Empfang ist völlig hin und das Modul gibt nur noch wirres Zeug aus.
>Ich messe den ganzen Impuls, im 10ms "Raster", nicht in 10ms "Abständen".
Ist genau das Gleiche! Du prüfst immer nur zu einem bestimmten
Zeitpunkt, einen evt. Defekt des Moduls erkennst du so sehr schlecht.
Kommt wohl immer drauf an wie man an die Sache 'rangeht. Ich prüfe nur
auf Fehler (auch die Prüfbits), das vereinfacht die Programmierung.
Ist wie bei vielen Sachen: jeder hat seine bevorzugten Methoden.
Schaut Euch doch mal die zahlreichen Beispiele in der Codesammlung an! Da gibt's genug Tipps...
Sonic wrote: > Ich will ja noch was Anderes machen als nur die Uhr laufen zu lassen, da > kann's mit der Rechenleistung schon mal knapp werden, bzw. für > Berechnungen etwas länger dauern. Also bei 4MHz Quarz und reichlich geschätzten 40 Zyklen für den 10ms Interrupt komme ich auf ne Wahnsinns-CPU-Belastung von 0,1% ! Kann mir keiner erzählen, daß er 0,1% merkt. Peter
@Peter: Ich weiß ja nicht ob du nur einzelne Programmfunktionen programmierst, bei mir laufen ab und zu auch mal mehrere Funktionen auf einem µC. Eine Uhr, se es DCF oder RTC odr beides zusammen sind reine Hintergrundfunktionen, die möglichst gar nicht ins Gewicht fallen sollten. Sobald ich meinen Programmablauf alle 10ms durch einen INT, sei er noch so kurz gehlten, unterbreche, sind andere zeitkritische Funktionen sehr schwer zu realisieren. Aber wie gesagt: jeder wie er will, mir isses halt nach meiner Methode lieber.
Sonic wrote: > sollten. Sobald ich meinen Programmablauf alle 10ms durch einen INT, sei > er noch so kurz gehlten, unterbreche, sind andere zeitkritische > Funktionen sehr schwer zu realisieren. Wenn ein Interrupt stört, dann isses vollkommen egal, wie oft er kommt. Ein 1s Interrupt stört genau so, er stört nur seltener. Wenn Interrupts stören, mußt Du entweder Dein Programm umstellen oder Interrupts zeitweise verbieten. Und nur, wenn dieses zeitweise Verbieten länger als 10ms dauert, geht der 10ms Interrupt in die Hose. Ich versuche allerdings das Hauptprogramm immer so zu schreiben, daß Interrupts nicht stören, egal welche. Peter P.S.: 10ms ist doch auch eine gute Zeit für die Tastenentprellung.
>>Ich messe den ganzen Impuls, im 10ms "Raster", nicht in 10ms "Abständen". >Ist genau das Gleiche! Du prüfst immer nur zu einem bestimmten >Zeitpunkt, einen evt. Defekt des Moduls erkennst du so sehr schlecht. Naja - ist es nicht. Der Timer guckt zwar nur alle 10ms, aber wenn die Impulse außerhalb der vorgegebenen Fenster - von 20ms nach oben und unten - liegen, wird dies auch als Fehler gesehen. Kommen ständig Fehlimpulse, ist der Empfang gestört oder das Modul defekt. Eindeutiger geht´s nicht.
Auf diese Weise ist bei Störungen schnell mal Null und Eins verwechselt. Merkst du dann erst über die Prüfbits.
Wieso, alles unter 8 ist Murks, 8,9,10,11,12 ist Null / größer 12 und kleiner 18 ist Murks, 18,19,20,21,22 ist Eins, alles über 22 ist Murks, rund um 100 ist die Austastsekunde 59 - willst Du´s noch genauer? Mein Controller verwechselt da nix und weiß eigentlich sofort, was Null und Eins ist. Wie gesagt: unter normalen Bedingungen empfange ich keine Fehlprotokolle, eine Kontroll-LED zeigt mir den aktuellen Status an. Die einzig nennenswerten Probleme treten bei Gewittern in unmittelbarer Nähe auf. Dann tritt die interne Quarzuhr in Betrieb.
Ich denke wir sollten es dabei bewenden lassen, dass beide Möglichkeiten gut funktionieren. Hier weiterzudiskutieren macht wenig Sinn. wie ich oben schon erwähnte, jeder ist halt von seiner Variante überzeugt. Möglicherweise ist von Fall zu Fall die Eine oder Andere Version angebrachter.
theoretisch klar ist bis jetzt alles.... hier mal eine neue Version:
1 | // Timer A0 interrupt service routine
|
2 | #pragma vector=TIMERA0_VECTOR
|
3 | __interrupt void Timer_A0 (void) |
4 | {
|
5 | _DINT(); |
6 | |
7 | intcount += 1; |
8 | |
9 | if(P2IN & 0x01) |
10 | {
|
11 | timecount += 1; |
12 | }
|
13 | |
14 | if(intcount > 98) |
15 | {
|
16 | if(timecount >= 8 && timecount <= 12) |
17 | {
|
18 | position(2,1); |
19 | printtext("0"); |
20 | timecount = 0; |
21 | }
|
22 | |
23 | if(timecount >= 18 && timecount <= 22) |
24 | {
|
25 | position(2,1); |
26 | printtext("1"); |
27 | timecount = 0; |
28 | }
|
29 | intcount = 0; |
30 | }
|
31 | |
32 | CCR0 = 327; |
33 | _EINT(); |
34 | }
|
Müsste soweit klappen.... teste grade
Christian S. wrote:
> klappt *freu*
Na bitte.
Ich habe auch die Erfahrung gemacht, daß die Timerpollmethode
störunempfindlicher ist, als die mit Capture.
Es müssen wesentlich mehr Störungen kommen, damit das Signal nicht mehr
dekodierbar ist.
Peter
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.