mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik DCF signalbeginn erkennung


Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe ein programm für einen AVR mega8 geschrieben, welches bei einer 
fallenden flanke an int0 einen timer startet, der 110ms läuft.
Nach 110ms wird geprüft ob das Signal noch high oder low ist.
Wenns noch low ist, ist es eine logische 1, wenns high ist, eine 
logische 0.

Das funktioniert soweit ganz gut und einwandfrei.

Jetzt möchte ich aber den Signalbeginn erkennen.
Dabei währe ja das Signal für mehr als 1050ms high.

Also habe ich mir gedacht, starte ich bei einer steigenden Flanke den 
Timer.
Nach 1050ms wird geschaut, ob ein low oder high anliegt.
High=Signalbeginn, Low=Kein Signalbeginn.

Leider funktioniert das nicht so richtig.
Habe das Port als Eingang konfiguriert und um die steigende Flanke zu 
erkennen ein 0x00 reingeschrieben.


Leider kommt nur murgs raus.

Seht ihr irgendeinen Fehler in der Methode?
(also ausser das es vielleicht kein guter Stil und resourcen 
verschwendend ist)

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fehler nich, aber das geht eleganter:
Lass den Timer mit Input Capture loslaufen. Zuerst stellste des Capture 
auf steigende Flanke. Im ersten Interrupt des Capture drehste auf 
fallende Flanke um und setzt den Timer auf Null. Beim nächsten Capture 
lieste den Timerwert ein und kannst logischerweise einfach vergleichen, 
obs kurz oder lang war.
Parallel dazu setzte mit demselben Timer noch ein Compare, das nach 
1100ms oder so greift (--> Timeout).

Du liest in den Capture-Interrupts damit dann die Bits ein und beim 
Compare weißt du, hier fängt ein neuer Datenblock an. Genau hier wirst 
du den alten Datenblock auch am besten auswerten.

Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm dann muss ich mir das mal genau begucken...


aber es muss doch auch ne super einfache methode geben, oder?

Autor: Helmut -dc3yc (dc3yc)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Methode vom Sven ist supereinfach und die Methode der Wahl!

Servus,
Helmut.

Autor: Sven P. (haku) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Weil ich (son ZUUUUUFALL aber auch) gerade nen Wecker am basteln bin.

Den Header pack ich grad hier rein.
/* main.h */
struct time_t {
  uint8_t seconds;
  uint8_t minutes;
  uint8_t hours;
};

struct time_buffer_t {
  uint8_t minutes;
  uint8_t hours;
};


Der DCF-Empfänger übernimmt eine neue Uhrzeit nur dann, wenn drei 
aufeinanderfolgende DCF-Datenrahmen korrekt empfangen wurden.

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist sie nicht. Im Falle von Empfangstörungen kann diese Methode den 
Controller in die Knie zwingen. Spikes in den Signalen lassen sich so 
auch nur schwer korrigieren. Lahme DCF-Signale liest man in einem 
Timer-Interrupt per Polling ein, da man meist sowieso einen Timer laufen 
hat. Die Länge der Bits erhält man über eine Zählvariable, die in der 
Timer-ISR mitläuft. Das kostet kaum Rechenzeit und der Ablauf des 
Programms wird so viel planbarer. Aber die Diskussion hatten wir hier 
schon mehr als einmal.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Travel Rec. wrote:
> Ist sie nicht. Im Falle von Empfangstörungen kann diese Methode den
> Controller in die Knie zwingen. Spikes in den Signalen lassen sich so
> auch nur schwer korrigieren.
Das ist definitiv wahr :-)

> Lahme DCF-Signale liest man in einem
> Timer-Interrupt per Polling ein, da man meist sowieso einen Timer laufen
> hat. Die Länge der Bits erhält man über eine Zählvariable, die in der
> Timer-ISR mitläuft. Das kostet kaum Rechenzeit und der Ablauf des
> Programms wird so viel planbarer. Aber die Diskussion hatten wir hier
> schon mehr als einmal.
Das werd ich demnächst ausprobieren.

Autor: Oliver D. (smasher)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

tut mir leid aber da bin ich nochmal :)

Also oben ist ein assembler programm, welches am atmel avr mega 8 ein 
DCF signal einliest und mir auf einem lcd ausgibt, ob gerade eine 0 oder 
1 gesendet wurde.

Das ganze klappt einwandfrei und prima.

Mir ist bewusst, dass das programm vielleicht nicht intelligent 
geschrieben ist, resourcen verschwendet und zum co2 ausstoß beiträgt 
ABER
es funktioniert. Und da ich erst seit wenigen Wochen mit avrs 
rumprobiere bin ich schon ein wenig froh das es klappt.


Nun versuche ich den Signalbeginn zu erkennen, was aber nicht klappt.
Oben stehend ist der funktionierende code.

Mein Gedanke war es nun, nur testweise, an meinem empfänger den anderen 
anschluss zu wählren (ich habe normal und invertiert) und den prescaler 
auf 256 zu stellen.
Dann währen bei einem 16mhz quarz ca. 251 überläufe 1030ms.
An diesem Zeitpunkte sollte ich nach erkennung einer negativen flanke 
checken, welchen status der pin hat.
Ist er low, ists ein signalbeginn.
Ist er high, kein signalbeginn.
Also müsste ich in meinem programm eigentlich nur den prescaler ändern, 
die überlaufzahl erhöhen und das programm sollte laufen. (und natürlich 
den anschluss am dcf wechseln).

Leider funktioniert das aber nicht :(
Die LCD funktion etc. macht keine probleme.

Vielleicht fällt ja jemandem ein, was Probleme machen könnte oder wo 
vielleicht ein konflikt durch die anderen Zählzeiten entsteht?


Also mal unter Abteilung: DCF Krams schauen und mir bitte bitte helfen 
:)


Danke.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, ich hab meine Routine mal umgestrickt und muss nun zurückrudern:
Die Flanken per Interrupt (INT, Input Capture) zu erkennen, ist MURKS.

Hier mal ein kommentiertes Schnippelchen:
/* die ISR wird alle halbe Millisekunde aufgerufen */
ISR(TIMER2_COMP_vect) {
  /* speichert den momentanen Zustand der Signalleitung */
  static uint8_t polarity = 1;

  /* zählt halbe Millisekunden */
  static uint16_t timer = 0;

  /* zählt die empfangenen Datenbits */
  static uint8_t position = 0xFF;



  /* wir zählen also durchgehend die halben Millisekunden */
  timer++;

  /* Wenn die Signalleitung gerade LOW ist... */
  if (!(PINB & _BV(PINB0))) {
    /* ...und sie vorher HIGH war... */
    if (polarity == 1) {
      /* ...dann hamwa hier ne fallende Flanke gefunden */
      /* Also: Timer neustarten */
      timer = 0;

      /* und den momentanen Zustand der Leitung merken */
      polarity = 0;
    }

    /* das wars fürs Erste */
    return;
  }


  /*
    Wenn wir hier landen, dann ist die Signalleitung gerade HIGH.
    Wenn sie nämlich LOW wäre, dann wärnwa oben schon mit "return"
    abgehauen.
  */

  /* also, die Leitung ist gerade High... */
  if (polarity == 1) {
    /* wenn sie das auch schon vorher war, gabs keine Pegeländerung */

    /* wenn sie nun schon zuuu lange ohne Pegeländerung HIGH war... */
    if (timer > (DCF_TIMEOUT * 2)) {
      /* ...dann ist das ein Timeout. */

      /* Also: ein neuer Datenblock beginnt. */
      position = 0;

      /* und das heißt, der vorherige Block ist zu Ende --> auswerten */
      evaluate_dcf();
     }

     /* und raus hier */
     return;
  }

  /*
    Wenn wir hier ankommen, ist die Leitung gerade HIGH, war aber
    vorher LOW. Also hamwa ne steigende Flanke gefunden.
  */

  /* Zustand merken */
  polarity = 1;


  /* Fehlen noch Bits im aktuellen Datenblock? */
  if (position > 58) {
    /* Nö --> zu viele Bits --> Fehler */
    return;
  }


  /* Nu guggenwa, obs lang oder kurz war */
  if (timer < (DCF_TIME_LOW * 2)) {
    /* kurz */
    dcf_data[position] = 0;
  }
  else if (timer > (DCF_TIME_HIGH * 2)) {
    /* lang */
    dcf_data[position] = 1;
  }
  else {
    /* irgendwas dazwischen --> Fehler */

    /*
      Indem wir position auf 255 setzen, fliegen wir dann weiter oben
      so lange raus (if position > 58), bis position beim Beginn eines
      neuen Datenblockes wieder auf 0 gesetzt wird.
    */
    position = 0xFF;
    return;
  }

  /* und Bits zählen */
  position++;
}

Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie gut das ich kein wort c spreche ;)

Also meinst du das es generell eine schlechte idee ist, per interrupt 
pin auf eine flanke zu warten und daraufhin einen timer zu starten?

Oder ist es nur schlecht per capture zu arbeiten?



Da bin ich ja froh jemand gefunden zu haben, der immoment den gleichen 
Kram an der Backe hat ;)

Autor: eProfi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich würde einen ganz anderen Ansatz wählen:
z.B. einen 1ms-Periodic-Interrupt, den kann man für alles mögliche 
brauchen.
In diesem Interrupt fragst Du das Pin ab und
addierst 1 auf eine Variable, wenn der Pin 1 war  oder
subtrahierst 1, wenn der Pin low war.

Dann setzt Du 2 Grenzen (Thresholds, auch dynamisch berechenbar), wenn 
diese über- bzw. unterschritten werden, hast Du Deinen Signalbeginn - 
zwar etwas zeitversetzt, aber wen interessiert das?

Vorteil: Entprellung: Spikes etc. werden einfach weggefiltert.

Einfacher geht's doch kaum.

P.s. Zu glauben, das Signal aus dem Empfänger sei immer exakt 100 oder 
200 ms lang, kann sich fatal auswirken. Das hängt von vielen Faktoren 
ab.
Deshalb würde ich die Grenzen dynamisch berechnen.

Autor: spess53 (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Viele Wege führen nach Rom. Auch deiner. Ich habe es vor einiger zum 
Test mal so programmiert (Anhang). Lief fehlerfrei.
Zur Information: ATMEGA16 bei 4.096 MHz. Timer1 läuft mit Vorteiler 
1024. OCR1A ist auf 150ms und ICR1 auf 1s eingestellt. Nach 150ms wird 
der DCF-Ausgang abgefragt und UDR übergeben. Im ICR1-Interrupt wird das 
T-Flag für die fehlende 59.Sekunde gesetzt. Gestartet wird durch 
EXT_INT0 (Timer und Prescaler auf 0 setzen).

Vielleicht hilft es dir.

MfG Spess

Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke ich schau gleich mal rein

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
cool! (das ist das kürzeste was ich je gesehen habe)

und was machst Du bei Störungen des Signals? Dann gibt Dein
Prog.Snip sinnlose Ergebnisse! Zeig doch mal den Rest der Quelle!

hochachtungsvoll Carsten

Autor: spess53 (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Kannst du haben. Das Ganze war allerdings nur dazu gedacht, die 
einzelnen Bits zum PC zu schicken. Hing mit dem Beitrag 
'Wetterinformatinon über DCF77', oder so ähnlich zusammen. Also keine 
Uhr. Und auch nur auf 'Funktionieren' programmiert.

MfG Spess

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das ging aber schnell, Danke

 spess53

habe das schon verstanden. Jetzt fehlt nur noch eine
vernünftige "Fehlerkorrektur" und "Auswertung" des
Signales, die Du leider in Deinem Code nicht drin hast.

Bezüglich Eurer Begierde (die Wetterinformation) das DCF77
zu decodieren, bin ich zu jeder "Schandtat" bereit, bin
aber nicht bereit, dafür Geld auszugeben. Wenn einer von
Euch so einen "Wetter-Chip" übrig hat und + und -, Eingang,-
Ausgang daran schreibt, würde ich mich auch gerne daran
beteiligen.

mfg Bit 1 bis 14

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Die 'Fehlerkorrektur' geht am einfachsten, wenn du eine Uhr mitlaufen 
lässt, die du mit gültigen DCF-Daten synchronisierst. Die unterste Stufe 
der Fehlererkennung wäre die Auswertung der Parity-Bits. Das nächste 
wäre eine Plausibilitätsprüfung: Auf einen 1.März kann kein 2.April 
folgen...
Nur als Hinweis: Die meisten erhältlichen Funkuhren laufen die meiste 
Zeit mit der internen Uhr.

MfG Spess

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
selber hi :)

in meinen Funkuhren verwende ich das Verfahren

_____________________
5 gültige Zeiten
(ohne Paritätsfehler der einzelnen Daten Blöcke)
nacheinander emfangen, dann lezte Zeit gültig!
______________________

läuft seit `88        :)

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Siehe oben: 'Viele Wege führen nach Rom'. Oder willst du dein Verfahren 
als einzig gültiges bezeichnen?

MfG Spess

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Niemals...


... aber es geht! :)

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

OK. War nicht böse gemeint.

MfG Spess

Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hoffe der liebe Spess53 ist öfters hier :)

Ich habe jetzt nicht mehr wirklich zeit deinen quellcode zu lesen und zu 
verstehen, weil ich bald in den urlaub fahre und noch so viel zu 
erldigen habe.
Wenn ich wieder da bin, kommen bestimmt die Fragen an dich ;)

Autor: Oliver D. (smasher)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ehm, wobei ich gerade feststelle, das der Code ja schon seeehr kurz ist 
!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.