Forum: Mikrocontroller und Digitale Elektronik 16-Bit Timer ATmega


von Bastoo (Gast)


Lesenswert?

Moin,

ich hab eine Frage zum Counter des ATmega640. Was passiert, wenn ich den 
den Timer 2 mal hintereinander starte? Es geht bei mir um das Toggeln 
zwischen zwei IRS und in jede startet den selben Timer, je nachdem 
welche ISR zuerst ausgeführt wurde. Ich möchte ganz gerne die zeitliche 
Differenz bestimmen, mit den diese beiden ISRs ausgelöst wurden.

Beispiel:

ISR1:
TCCR1B |= 0x01;
variable1 = TCNT1;

ISR2: //wird kurz nach der ISR1 ausgeloest
TCCR1B |= 0x01;
variable2 = TCNT1;

Anschließend nehme ich die Differenz, je nachdem welche ISR zuerst 
ausgeführt wurde (minus der Zeit, die die Instruktionen zum starten der 
jeweils anderen ISR und das schreiben des Registerwertes in TCCR1B 
benötigen). Is wohl etwas unsauber, ich weiss. Aber funktioniert dieses 
Prizip generell oder wird der Timer beim zweiten Start zurückgesetzt?

Wenns unverständlich ist, dann male ich gern ein Bild. :)

Danke im Vorraus!!

von spess53 (Gast)


Lesenswert?

Hi

Was soll da passieren? Mehr als den Takt freigeben geht nicht.

MfG Spess

von Wusel D. (stefanfrings_de)


Lesenswert?

Schau Dir deinen Code genau an, da steht nämlich die Antwort drin:
1
TCCR1B |= 0x01;
2
...
3
TCCR1B |= 0x01;

Hier wird das Register TCCR1B mit 0x01 per ODER Funktion Verknüpft. Was 
macht die ODER Funktion mit den Bits?

Ausgangszustand Timer gestoppt, Bit 0 = 0.
Timer Starten: 0 ODER 1 = 1
Timer nochmal starten: 1 ODER 1 = 1

Das heisst, wenn Du den gleichen Befehl zweimal nacheinander ausführst, 
ist der zweite völlig Wirkungslos.

von Fabian O. (xfr)


Lesenswert?

Du musst den Timer nicht in den ISRs starten. Einmal zu Beginn des 
Programms reicht. Die Anweisung
1
TCCR1B |= 0x01;
bewirkt nichts, wenn das Bit vorher schon gesetzt war. Der Counter wird 
dadurch nicht zurückgesetzt.

von Bastoo (Gast)


Lesenswert?

Fabian O. schrieb:
> Einmal zu Beginn des
> Programms reicht.

Geht Leider nicht. Ich möchte eine genaue Differenzzeit bestimmen, 
welche ISR zu erst und welche als zweites ausgelöst wurde. Wenn ich den 
Timer ausserhalb der ISR starte, so gibt es bei 8 MHZ alle 125 ns * 2^16 
= ca. 8,1 ms einen Überlauf. Wenn ich in die ISR springe, so kann der 
Zählerwert meinetwegen gerade bei 65000 sein und wenn die zweite ISR 
gestartet wurde bei wieder bei 100. Jetzt könnte ich die OVFs zählen, 
stimmt. Aber ich denke die 8,1 ms reichen mir aus. Mit einen größeren 
zeitlichen Versatz starten die beiden ISRs nicht voneinander, so dass 
ich den Timer erst innerhalb der ISR starten kann. Ich muss diesen in 
beiden ISRs starten, da ich nicht weiss, welche zu erst ausgelöst wird! 
:)

von Bastoo (Gast)


Lesenswert?

Weiss jemand, wie lange der interne Komparator des ATmege ca. braucht, 
bis eine ISR gestartet wird (nachdem die Differenzspannung am Eingang 
das Vorzeichen wechselt)? Hab da leider keine Angaben im Datenblatt zu 
gefunden. Auch nichts über den Offset.

von spess53 (Gast)


Lesenswert?

Hi

> so gibt es bei 8 MHZ alle 125 ns * 2^16
>= ca. 8,1 ms einen Überlauf. Wenn ich in die ISR springe, so kann der
>Zählerwert meinetwegen gerade bei 65000 sein und wenn die zweite ISR
>gestartet wurde bei wieder bei 100.

Dein Code-Fetzen verhindert auch keinen Überlauf. Das Setzen des CS-Bits 
beeinflußt den Zählerstand des Timers nicht. Also kann der durchaus auch 
mal bei 65535 starten.

MfG Spess

von Bastoo (Gast)


Lesenswert?

Der Code is schon noch etwas länger. Also jede ISR wird nur einmal 
ausgelöst, der zeitliche Unterschied ist <8 ms. Nachdem die zeitliche 
Differenz ermittelt wurde, wird der Zähler wieder zurückgesetzt und die 
beiden ISR können wieder auslösen. Eigentlich dürfte dann doch kein 
Überlauf eintreten, oder?

von Fabian O. (xfr)


Lesenswert?

Bastoo schrieb:
> Wenn ich in die ISR springe, so kann der
> Zählerwert meinetwegen gerade bei 65000 sein und wenn die zweite ISR
> gestartet wurde bei wieder bei 100.

Macht ja nichts, die Differenz stimmt trotzdem. Allerdings musst Du 
wissen, welcher Wert vorher und welcher nachher war. Entweder speichst 
Du das in einer eigenen Variable, oder Du weißt, dass die Differenz 
unter 4 ms ist. Dann nimmst Du von beiden Möglichkeiten die kleinere.

Aber wenn Du die Differenz nur einmalig ermitteln willst, geht es 
natürlich auch so, wie Du es machen willst. Ansonsten musst Du nach den 
beiden ISRs den Timer stoppen und den Zähler wieder auf Null setzen.

von Bastoo (Gast)


Lesenswert?

Super, danke euch!
Habt ihr vielleicht noch eine Idee, wie ich an die technischen Daten vom 
AC des ATmega kommen kann?

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:
> Fabian O. schrieb:
>> Einmal zu Beginn des
>> Programms reicht.
>
> Geht Leider nicht.

Es geht praktisch immer.

> so gibt es bei 8 MHZ alle 125 ns * 2^16 = ca. 8,1 ms einen Überlauf.

OK.

> Aber ich denke die 8,1 ms reichen mir aus.

Na, dann ist doch alles in Butter!

> Wenn ich in die ISR springe, so kann der
> Zählerwert meinetwegen gerade bei 65000 sein

ja, macht ja nix

> und wenn die zweite ISR
> gestartet wurde bei wieder bei 100.

Auch ok. Wo liegt das Problem?

> Jetzt könnte ich die OVFs zählen, stimmt.

Nö. Wenn du dir sicher bist, dass du über die 8.1ms nie drüber kommen 
wirst, dann rechnest du einfach
   differenz = ende - start
und kriegst bei 16 Bit unsigned Arithmetik immer das richtige Ergebnis 
raus. Selbst dann wenn der Timer zwischendurch einmalig übergelaufen 
ist. Diesen einen Overflow brauchst du überhaupt nicht berücksichtigen.


> wird der Zähler wieder zurückgesetzt und die

Spars dir.
Starte den Timer beim Programmstart und lass ihn laufen.
Dieses ganze Gemurkse mit Timer starten/stoppen/zurücksetzen ist alles 
den Aufwand nicht wert.

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:
> Fabian O. schrieb:
>> Einmal zu Beginn des
>> Programms reicht.
>
> Geht Leider nicht. Ich möchte eine genaue Differenzzeit bestimmen

Wie genau?
Sobald du in den Bereich kommst, dass deine Genauigkeitsanforderungen in 
die Größenordnung von ca. (ich würde mal sagen) 10 Takzyklen des µC 
kommen, wirds haarig. Denn vom Auslösen des Interrupts bis zum 
Bearbeiten vergehen ein paar Takte, die aber nicht immer gleich viele 
sind. Das kann man noch mit einem Input Capture lösen. Aber sobald die 
zeitlichen Unterschiede zwischen den Flanken sich ebenfalls in diesem 
Bereich bewegen, dann hilft dir auch der Capture nichts mehr, weil du 
dann nicht mehr feststellen kannst, welche Flanke zuerst kam bzw. das 
Capture Register nicht mehr schnell genug auslesen kannst. Da geht nur 
noch externe Hardware oder ein wesentlich schnellerer Prozessor.

Die Forderung nach "möglichst genau" ist
* meistens nicht sinnvoll,
* nur mit erheblichem Hardwareaufwand zu erreichen
* dann allerdings nicht zu bezahlen und
* meist auch gar nicht notwendig

von Bastoo (Gast)


Lesenswert?

Ich führe in jeder ISR eine Subtraktion durch. Ungefähr so:

ISR1:
TCCR1B |= 0x01;
variable1 = TCNT1;
(sprung in ISR2, wenn ISR2 nicht als erstes ausgelöst wurde. Zeitpunkt 
<8 ms)
Differenz = variable2 - variable1;

ISR2: //wird kurz nach der ISR1 ausgeloest
TCCR1B |= 0x01;
variable2 = TCNT1;
(sprung in ISR1, wenn ISR1 nicht als erstes ausgelöst wurde. Zeitpunkt 
<8 ms)
Differenz = variable1 - variable2;

Wenn ISR1 zuerst auslöst, die Variable 1 jetzt 65000 ist und die 
Variable2 aber 100, dann bekomme ich doch einen falschen wert raus. auch 
bei unsigned, oder nicht? Es wird ja gerechnet 100-65000.

von Bastoo (Gast)


Lesenswert?

Ja, so genau muss es garnicht sein. Ich hab über den Assambler Code 
schon geschaut, welche Instruktionen zwischen den ISRs ausgeführt 
werden. Diese ziehe ich natürlich nochmal vom Gesamtwert ab.

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:

> Wenn ISR1 zuerst auslöst, die Variable 1 jetzt 65000 ist und die
> Variable2 aber 100, dann bekomme ich doch einen falschen wert raus.

Nö.

> auch
> bei unsigned, oder nicht? Es wird ja gerechnet 100-65000.

Ja und.
das Ergebnis von 100-65000 (16 Bit unsigned gerechnet) ist 636
Und genau so viele Zählschritte liegen auch zwischen 65000 und 100

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:
> Ja, so genau muss es garnicht sein.

Nochmal:
Wie genau?

Spezifizier das in Form einer Zahlenangabe. Sonst reden wir aneinander 
vorbei. Geht es um µs, um ms, um Sekunden, Stunden, Tage?
Wieviele µs?

Wenn du bei 16Mhz auf 1/10 µs genau messen willst, dann ist wird das 
Verfahren anders aussehen, als wie wenn dir ein Jitter von 1µs egal ist.


Was, exakt, willst du messen, dass du eine Zeitdifferenz mit einer 
Genauigkeit von 1 Millionstel Sekunde (oder noch besser) feststellen 
können musst?
Und welches ist die kleinste Zeitdiffernz, die in deiner Messung 
PRAKTISCH gesehen vorkommen wird?

von Bastoo (Gast)


Lesenswert?

Die kleinste Differenz, die ich bisher gemessen habe (die Instruktionen 
zwischen den beiden Zeitmessungen abgezogen), beträgt 8 µs. Die größte 
Zeitdifferenz beträgt 4000 µs.

von Bastoo (Gast)


Lesenswert?

Ist eine Genauigkeit von 5-10 µs möglich?

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:
> Ist eine Genauigkeit von 5-10 µs möglich?

Das sind 80 bis 160 CPU/Timertakte.
Daher: Ja, das ist kein Problem. Führ beide Signale mittels Dioden-Or 
zusätzlich zusammen auf den Input Capture und in der ISR holst du dir 
das Capture Ergebnis und siehst an den regulären Pins nach, welcher Pin 
das Capture Ereignis ausgelöst hat.
Du brauchst keine Code-Laufzeiten berücksichtigen oder Interrupt 
Latenzen einrechnen. Der Timer Input Capture merkt sich den Zählerstand, 
an dem das Ereignis eingetreten ist. Die Minimal-Zeit Differenz ergibt 
sich aus dem Zeitbedarf, den dein Programm braucht, bis es sich das 
Capture Ergebnis abholen kann. Das ist das Minimum, unter welches du mit 
dem Input Capture nicht kommst. Dafür ist das komfortabel und Straight 
Forward zu programmieren.

von Bastoo (Gast)


Lesenswert?

:) Danke Dir Karl!

Btw. ich arbeite mit 8 MHz und die Platine ist schon fertig. Das mit der 
Zeitdifferenzmessung war nicht unbedingt nötig und wurde, da noch etwas 
Zeit für das Projekt über war, erst später realisiert. Daher ist es auch 
nicht unbedingt ein "must-have" im Projekt. Da ich es aber implementiert 
habe, interessiert mich die Genauigkeit doch schon ein wenig. Aber wenn 
die Ungenauigkeit < 10 µs ist, dann bin ich zufrieden.

von Falk B. (falk)


Lesenswert?

@  Bastoo (Gast)

>Weiss jemand, wie lange der interne Komparator des ATmege ca. braucht,
>bis eine ISR gestartet wird (nachdem die Differenzspannung am Eingang
>das Vorzeichen wechselt)?

Ist wie ein normaler externer Interrupt. Der Einsprung dauert 4 Takte.

> Hab da leider keine Angaben im Datenblatt zu
>gefunden. Auch nichts über den Offset.

Siehe Datenblatt "Analog Comparator Input Offset Voltage", max. 40mV.

MFG
Falk

von Karl H. (kbuchegg)


Lesenswert?

Bastoo schrieb:
> :) Danke Dir Karl!
>
> Btw. ich arbeite mit 8 MHz und die Platine ist schon fertig.

OK.
Also 40 bis 80 µC Takte. Sollte immer noch reichen, um eine schöne 
Capture Auswertung zu machen, wenn du die Hardware noch zubauen 
könntest.

Sonst eben mit den Interrupts. Geht natürlich auch, wenn auch nicht so 
taktgenau wie mit dem Capture. Der Vorteil vom Input Capture besteht nun 
mal darin, dass die Hardware den exakten Zählerstand festhält, an dem 
die Flanke im Signal kam. D.h. wenn dein µC danach ein paar Takte 
braucht, bis er dann endlich soweit ist ein Register vom Timer 
auszulesen, dann spielt das keine große Rolle, weil du ja auf diesen, 
vom Timer selbst festgehaltenen Wert zugreifst und dir den holst. Und 
der ist genau der Wert, an dem die Flanke per Hardware registriert 
wurde.

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.