Forum: Mikrocontroller und Digitale Elektronik Impulslängen DCF 77


von Christian S. (aliendrummer)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

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.

von Christian S. (aliendrummer)


Lesenswert?

ne ...ist n msp 430

von Sonic (Gast)


Lesenswert?

Kann ich leider nicht weiterhelfen.

von Peter D. (peda)


Lesenswert?

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

von Christian S. (aliendrummer)


Lesenswert?

undwie triggerst du den timer? mit nem externen Int.?

von Peter D. (peda)


Lesenswert?

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

von Christian S. (aliendrummer)


Lesenswert?

so ganz peil ichs nciht.... könntest du ein code - snipplet posten?

von Karl H. (kbuchegg)


Lesenswert?

Gibt es im MSP430 keine Timer die regelmässig einen
Interrupt auslösen können?

von Christian S. (aliendrummer)


Lesenswert?

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

von Christian S. (aliendrummer)


Lesenswert?

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
}

von Peter D. (peda)


Lesenswert?


von Karl H. (kbuchegg)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

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.

von TravelRec. (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

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

von Pit H. (pit9)


Lesenswert?

Schaut Euch doch mal die zahlreichen Beispiele in der Codesammlung an! 
Da gibt's genug Tipps...

von Peter D. (peda)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von TravelRec. (Gast)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

Auf diese Weise ist bei Störungen schnell mal Null und Eins verwechselt. 
Merkst du dann erst über die Prüfbits.

von TravelRec. (Gast)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

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.

von Christian S. (aliendrummer)


Lesenswert?

BACK TO TOPIC!!! HELFT MIR LIEBER ;)

von Philipp B. (philipp_burch)


Lesenswert?

Es wurden doch mehrere Lösungen gepostet, was ist nicht klar?

von Christian S. (aliendrummer)


Lesenswert?

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

von Christian S. (aliendrummer)


Lesenswert?

klappt freu

von Peter D. (peda)


Lesenswert?

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

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

100% ACK - aber gut nun ;-)

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.