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)
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.
hmm dann muss ich mir das mal genau begucken... aber es muss doch auch ne super einfache methode geben, oder?
Die Methode vom Sven ist supereinfach und die Methode der Wahl! Servus, Helmut.
Weil ich (son ZUUUUUFALL aber auch) gerade nen Wecker am basteln bin. Den Header pack ich grad hier rein.
1 | /* main.h */
|
2 | struct time_t { |
3 | uint8_t seconds; |
4 | uint8_t minutes; |
5 | uint8_t hours; |
6 | };
|
7 | |
8 | struct time_buffer_t { |
9 | uint8_t minutes; |
10 | uint8_t hours; |
11 | };
|
Der DCF-Empfänger übernimmt eine neue Uhrzeit nur dann, wenn drei aufeinanderfolgende DCF-Datenrahmen korrekt empfangen wurden.
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.
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.
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.
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:
1 | /* die ISR wird alle halbe Millisekunde aufgerufen */
|
2 | ISR(TIMER2_COMP_vect) { |
3 | /* speichert den momentanen Zustand der Signalleitung */
|
4 | static uint8_t polarity = 1; |
5 | |
6 | /* zählt halbe Millisekunden */
|
7 | static uint16_t timer = 0; |
8 | |
9 | /* zählt die empfangenen Datenbits */
|
10 | static uint8_t position = 0xFF; |
11 | |
12 | |
13 | |
14 | /* wir zählen also durchgehend die halben Millisekunden */
|
15 | timer++; |
16 | |
17 | /* Wenn die Signalleitung gerade LOW ist... */
|
18 | if (!(PINB & _BV(PINB0))) { |
19 | /* ...und sie vorher HIGH war... */
|
20 | if (polarity == 1) { |
21 | /* ...dann hamwa hier ne fallende Flanke gefunden */
|
22 | /* Also: Timer neustarten */
|
23 | timer = 0; |
24 | |
25 | /* und den momentanen Zustand der Leitung merken */
|
26 | polarity = 0; |
27 | }
|
28 | |
29 | /* das wars fürs Erste */
|
30 | return; |
31 | }
|
32 | |
33 | |
34 | /*
|
35 | Wenn wir hier landen, dann ist die Signalleitung gerade HIGH.
|
36 | Wenn sie nämlich LOW wäre, dann wärnwa oben schon mit "return"
|
37 | abgehauen.
|
38 | */
|
39 | |
40 | /* also, die Leitung ist gerade High... */
|
41 | if (polarity == 1) { |
42 | /* wenn sie das auch schon vorher war, gabs keine Pegeländerung */
|
43 | |
44 | /* wenn sie nun schon zuuu lange ohne Pegeländerung HIGH war... */
|
45 | if (timer > (DCF_TIMEOUT * 2)) { |
46 | /* ...dann ist das ein Timeout. */
|
47 | |
48 | /* Also: ein neuer Datenblock beginnt. */
|
49 | position = 0; |
50 | |
51 | /* und das heißt, der vorherige Block ist zu Ende --> auswerten */
|
52 | evaluate_dcf(); |
53 | }
|
54 | |
55 | /* und raus hier */
|
56 | return; |
57 | }
|
58 | |
59 | /*
|
60 | Wenn wir hier ankommen, ist die Leitung gerade HIGH, war aber
|
61 | vorher LOW. Also hamwa ne steigende Flanke gefunden.
|
62 | */
|
63 | |
64 | /* Zustand merken */
|
65 | polarity = 1; |
66 | |
67 | |
68 | /* Fehlen noch Bits im aktuellen Datenblock? */
|
69 | if (position > 58) { |
70 | /* Nö --> zu viele Bits --> Fehler */
|
71 | return; |
72 | }
|
73 | |
74 | |
75 | /* Nu guggenwa, obs lang oder kurz war */
|
76 | if (timer < (DCF_TIME_LOW * 2)) { |
77 | /* kurz */
|
78 | dcf_data[position] = 0; |
79 | }
|
80 | else if (timer > (DCF_TIME_HIGH * 2)) { |
81 | /* lang */
|
82 | dcf_data[position] = 1; |
83 | }
|
84 | else { |
85 | /* irgendwas dazwischen --> Fehler */
|
86 | |
87 | /*
|
88 | Indem wir position auf 255 setzen, fliegen wir dann weiter oben
|
89 | so lange raus (if position > 58), bis position beim Beginn eines
|
90 | neuen Datenblockes wieder auf 0 gesetzt wird.
|
91 | */
|
92 | position = 0xFF; |
93 | return; |
94 | }
|
95 | |
96 | /* und Bits zählen */
|
97 | position++; |
98 | }
|
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 ;)
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.
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
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
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
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
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
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 :)
Hi Siehe oben: 'Viele Wege führen nach Rom'. Oder willst du dein Verfahren als einzig gültiges bezeichnen? MfG Spess
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 ;)
Ehm, wobei ich gerade feststelle, das der Code ja schon seeehr kurz ist !
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.