Hallo, ich versuche, die Dauer von high-Perioden an einem ATmega644-Port mittels eines 16-bit-Timers auszuzählen. Hier der kurze Code: //###### 16-bit-Zähler für Flügelrad unsigned long highabfrage(void) { unsigned long high = 0; DDRD &= 127; // PORTD7 wird Eingang while ( !(PIND & 1<<PD7)); // warte auf high TIFR1 = 1; // nach overflow manuell rücksetzen TCCR1B |= (1<<CS12) | (1<<CS10); // Timerstart mit 1/1024 while ((PIND & 1<<PD7) && !(TIFR1 & 1<<TOV1)); // warte auf low // oder T-overflow TCCR1B = 0; // Timer stop high = TCNT1L + (TCNT1H<<8); // auslesen return (high); } Die zu erfassenden high-Perioden sind z.Zt. 87 ms lang, die Timerfrequenz ist 16 MHz / 1024 = ca 15 kHz, also 67 mysec/Takt. Demnach sollte der Timer typischerweise bis 1300 kommen, bevor Port D7 low wird. Bei Sensorschaden bleibt der Port D7 high und die Schleife endet durch Timeroverflow. Ein Interrupt wird nicht ausgelöst, deshalb die manuelle Rückstellung von TIFR. Ein Interrupt während der Timerauslesens findet auch nicht statt. Da ich nicht sicher war, ob der Zähler mit 0 startet, habe ich ihn auch mal manuell auf Null gestellt, hat aber auch nicht geholfen. Die ausgebenen Zahlen schwanken wild, von den relativ konstanten high-Perioden keine Spur. Was mache ich hier falsch? Gibt es irgendwo, in einem verborgenen Winkel, den ich nicht gefunden habe, Beispielcode? Gruß Egon
>Da ich nicht sicher war, ob der Zähler mit 0 startet, >habe ich ihn auch mal manuell auf Null gestellt, hat aber auch nicht >geholfen. Der Zähler startet nach einem Reset mit Null, danach aber zählt er immer von dem Zählerstand weiter, den er gerade hat. Insofern musst du das Null-Stellen am Anfang der Funktion wieder einbauen.
1 | high = TCNT1L + (TCNT1H<<8); |
geht auch einfacher mit
1 | high = TCNT1; |
Damit kannst du sicher sein, daß TCNT1L vor TCNT1H gelesen wird. Bei deiner handgestrickten Version darf der Compiler das umstellen (auch wenn er es sehr wahrscheinlich nicht tut). Du bist dir sicher, daß deine Signale nicht prellen? Oliver
Noch was: Für den 16-Bit-Zähler reicht ein unsigned int. Da braucht es kein long. Empfehlenswert ist die Verwendung der Typen aus stdint.h, in deinem Fall uint16_t. Damit gibt es weniger Verwirrung, wie groß nun welcher Datentyp ist. Oliver
Hallo Ernst, ärgerlicherweise erst zu spät. Normalerweise falle ich begierig über neue Antworten her. Schade, dann hätte ich die Sache mit dem Rücksetzen des TIFR1 nicht aus dem Manual klauben müssen. Nichts gefunden habe ich über den Startwert des Zählers. Bist Du sicher, daß der Zähler vor dem Starten erst auf Null gesetzt werden muß? Immerhin könnte das meine Zufallszahlen erklären, aber anderseits müßte dann doch wenigstens hin und wider für high 65536 zu lesen sein, wenn er immer weiterzählt und dadurch Überlauf und Schleifenabbruch erreicht. Was bekommt man eigentlich, wenn man auf einen Overflow reagiert und sofort den Zähler anhält und ausliest? Etwa Null, weil er dann schon resettet ist? Auf das Auslesen von TCNT1 nach der 8-bit-Methode war ich verfallen, weil es mit 16-bit nicht funktioniert hatte. Aber da hatte ich mich bloß bei der Variablenbenennung vertan, da ich nicht nur L und H, sondern auch noch die "1" weggelassen hatte. @hi Oliver auf dem Oszi sind sehr schöne Rechteckkurven zu sehen, allerdings kriege ich ein gewisses Zittern nicht heraus - aber das dürfte dem ATmega egal sein. Erst mal vielen Dank für Eure Hilfe, ich melde mich nach dem Ausprobieren wieder Viele Grüße Egon
Egon Müller schrieb: > Nichts gefunden habe ich über den Startwert des Zählers. Bist Du sicher, > daß der Zähler vor dem Starten erst auf Null gesetzt werden muß? Ja. (abgesehen vom allerersten Start natürlich) > Immerhin könnte das meine Zufallszahlen erklären, aber anderseits müßte > dann doch wenigstens hin und wider für high 65536 zu lesen sein, wenn er > immer weiterzählt und dadurch Überlauf und Schleifenabbruch erreicht. > Was bekommt man eigentlich, wenn man auf einen Overflow reagiert und > sofort den Zähler anhält und ausliest? Etwa Null, weil er dann schon > resettet ist? Auch nach einem Überlauf läuft der Timer munter weiter. Bei einem Prescaler von 1024 hast du ja aber genug Zeit, auf das Overflow-Flag zu reagieren. Du solltest dann also tatsächlich 0 auslesen. Apropos Prescaler: 1024? Im anderen Thread hattest du noch Sorge um deine Auflösung wegen einer Hand voll zusätzlicher Cycles in der manuellen Zählschleife und jetzt setzt du die Auflösung auf 1/1024?
Stefan Ernst schrieb: ? > > Auch nach einem Überlauf läuft der Timer munter weiter. Bei einem > Prescaler von 1024 hast du ja aber genug Zeit, auf das Overflow-Flag zu > reagieren. Du solltest dann also tatsächlich 0 auslesen. Eigentlich wäre es mir lieber gewesen, ich würde den vollen Zählerwert von 65536 auslesen können, aber das geht wohl nicht. Schade > > Apropos Prescaler: 1024? Im anderen Thread hattest du noch Sorge um > deine Auflösung wegen einer Hand voll zusätzlicher Cycles in der > manuellen Zählschleife und jetzt setzt du die Auflösung auf 1/1024? Hatte ich zwischendurch zum Testen so niedrig gesetzt, weil das Zählergebenis so aussah, als würden da irgendwelche Variablen ihren Wertebereich verlassen. Aber wenn jetzt der Zähler als Übeltäter identifiziert ist.... Viele Grüße Egon
Stefan Ernst schrieb: > Nur so nebenbei: > Der höchste Wert bei 16 Bit ist 65535. Bei 16 bit kann ich mir nur "65000-ungrad" merken. Aber Du hast schon recht. Schade, daß man an diesen Wert bei Timeroverflow nicht herankommt - hätte sich im übrigen Programm gut gemacht. Übrgigens: Ich werde mich doch noch mit dem Watchdog vertraut machen müssen - wegen eines anderen Sensors. Aber ich finde einfach keine Tutorials, z.B., wie man mit ISR umgeht usw. Wenigsten ist im Manual zu lesen, daß der Watchdog des ATmega644Bei nicht nur einen Reset, sondern auch einen Interrupt auslösen kann. Die Dinger werden immer besser. Viele Grüße Egon
Einerseits gibt es für solche Sachen die InputCapture-Einheit, andererseits kann man sowas wirklich einfach selber basteln: Timer Initialisieren und laufen lassen. In Schleife auf l-Pegel warten // da man ja mitten im Impuls zu messen anfangen könnte In Schleife auf H-Pegel warten // positive Flanke erkennen... Timerwert in erster Variablen sichern In Schleife auf L-Pegel warten Timerwert in zweiter Variablen sichern Differnz zweite Variable - erste Variable errechnen Rückgabe der Differenz
STK500-Besitzer schrieb: > Einerseits gibt es für solche Sachen die InputCapture-Einheit, Ja, benutze ich auch in einer anderen Schaltung und es funktioniert bestens. Nachteil: es gibt nur einen Pin für input capture, man braucht einen Logikbaustein der die eingehenden Signale nacheinander auf diesen Pin legt, wobei man von dem Logikbaustein verlangen muß, daß sich seine Ausgänge zusammnenschalten lassen. Erfreulicherweise habe ich dann noch bei einen Ditributor diesen Baustein gefunden. > andererseits kann man sowas wirklich einfach selber basteln: > > Timer Initialisieren und laufen lassen. > > In Schleife auf l-Pegel warten // da man ja mitten im Impuls zu messen > anfangen könnte > > In Schleife auf H-Pegel warten // positive Flanke erkennen... > Timerwert in erster Variablen sichern > In Schleife auf L-Pegel warten > Timerwert in zweiter Variablen sichern > > Differnz zweite Variable - erste Variable errechnen > > Rückgabe der Differenz Früher hatte ich eine Eigenbaulösung, wo ich während der High-Periode ganz einfach eine Variable incrementiert hatte - was auch ging. Hier im Forum hat man mir empfohlen, einen Timer zu benutzten. Das tue ich jetzt; jedesmal, bevor ich ihn starte, setze ihn auf Null. Dann kann ich als Nebeneffekt das Zählen bei Sensorschaden (=Dauerhigh) abbrechen, sozusagen als Watchdogersatz für jemanden, der noch keine rechten Gebrauchsanweisungen für Interrupthandling gefunden hat. Viele Grüße Egon
Egon Müller schrieb: > sozusagen als Watchdogersatz für jemanden, der noch keine rechten > Gebrauchsanweisungen für Interrupthandling gefunden hat. > > > Viele Grüße > Egon Erledigt - meine alten Tutorialausdrucke waren schon sehr veraltet. In den aktualisierten Tutorials steht alles, was mir gefehlt hatte! Egon
Egon Müller schrieb: > STK500-Besitzer schrieb: >> Einerseits gibt es für solche Sachen die InputCapture-Einheit, > > Ja, benutze ich auch in einer anderen Schaltung und es funktioniert > bestens. > Nachteil: es gibt nur einen Pin für input capture, man braucht einen > Logikbaustein der die eingehenden Signale nacheinander auf diesen Pin > legt, wobei man von dem Logikbaustein verlangen muß, daß sich seine > Ausgänge zusammnenschalten lassen. Erfreulicherweise habe ich dann noch > bei einen Ditributor diesen Baustein gefunden. Falls du den ADC nicht verwendest zu dem Zeitpunkt kannst du einfach den ADC deaktivieren und über dessen Input-MUX eines von 6 oder 8 Signalen zum AC durchschleifen. Der Ausgang des AC wird schliesslich zum InCapt verdrahtet. Es braucht da keine externe Hardware wie Analog-Multiplexer à la 4051 oder so. Johann
Johann L. schrieb: > Falls du den ADC nicht verwendest zu dem Zeitpunkt kannst du einfach den > ADC deaktivieren und über dessen Input-MUX eines von 6 oder 8 Signalen > zum AC durchschleifen. Der Ausgang des AC wird schliesslich zum InCapt > verdrahtet. > Interessant, werde mal über den Input-MUX nachlesen, vielen Dank! Gruß Egon
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.