Wie viele Takte ergeben 1500 µs?

Gast #4714401
Lesenswert?

Ich bin gerade etwas verwirrt. Ich habe einen ATMEGA328P mit einem 
20-MHz-Quarz und möchte etwas trickreich eine gewisse Anzahl von 
Mikrosekunden abwarten. Um den Programmablauf nicht zu unterbrechen, 
soll das per Timer-Interrupt passieren. Aus verschiedenen Gründen steht 
mir nur noch Timer2 zur Verfügung.
Das Ganze dient dazu, einen Servo anzusteuern.

Beim Programmstart initialisiere ich meinen Timer mit:
1
TCCR2A = 0;
2
TCCR2B = _BV(CS21) | _BV(CS20); // Prescaler 1/32

Für einen Impuls resette ich TCNT2, setze meinen Ausgang auf High und 
aktiviere den Interrupt.
Im Interrupthandler wird die Zahl der Überlaufe gezählt und bei 
Erreichen der gewünschten Zahl wird der Ausgang wieder auf Low gesetzt 
und der Interrupt deaktiviert.
1
static volatile uint8_t Overflows;
2

3
ISR(TIMER2_OVF_vect) {
4
  if (--Overflows > 0) return;
5

6
  LO(PIN_SERVO); // Ist ein Makro
7
  TIMSK2 = 0;
8
}

Ich habe (durch Ausprobieren) herausgefunden, dass mein Servo bei 40000 
CPU-Takten in Mittelstellung (genau zwischen den Endanschlägen) geht:
1
Overflows = 5;
2
TCNT2 = 30;
3
HI(PIN_SERVO); // Ist ein Makro
4
TIMSK2 = _BV(TOIE2);

Der Timer zählt also insgesamt 5*256-30 = 1250 Mal, also 40000 Takte 
(Prescaler 1/32). 40000 Takte sind bei 20 MHz aber 2000 µs und nicht 
1500 µs (was laut Datenblatt die Mittelstellung sein soll). Es stimmt 
aber definitiv, denn bei der halben Zeit (1000 µs) versucht das Servo 
schon über den Endanschlag zu fahren und rattert und knackt 
besorgniserregend.

Wo habe ich falsch gerechnet?
Gast #4714408
Lesenswert?

Ich glaube, deine Rechnung ist falsch. Könnte also gut sein, dass der µC 
gar nicht mit 20Mhz läuft (warum auch immer).

Lass mal einfach eine LED mit sleep() Blinken, ohne Timer. Wenn sie dann 
mit der falschen Geschwindigkeit blinkt, stimmt war mit deinem Taktgeber 
nicht.
Gast #4714461
Lesenswert?

Auch dann würde die Uhr nachgehen und das Servo zudem sehr unregelmäßig 
herumhampeln. Ist aber beides nicht der Fall.
Um das auszuschließen, werde ich heute Abend aber nochmal die 
idiotensichere Variante mit _delay_us() probieren.

Was mich im Datenblatt verdutzt, ist die Zeile (Seite 3):

"Operating travel: 90° (1000 -> 2000 µs)"

Das halte ich aber für einen Schreibfehler und eigentlich sollte da 
sicher 180° stehen. Wer solche Fehler macht, baut aber vielleicht auch 
Servos mit Mittelstellung bei 2000 µs?
Gast #4714480
Lesenswert?

>  Wer solche Fehler macht, baut aber vielleicht auch
> Servos mit Mittelstellung bei 2000 µs?

Dann würde der Servo an normalen Fernbedienungen unbrauchbar sein.

> 4 komplette Durchläufe sind dann 409,6 * 4 = 1,638ms
> also knapp neben der Mittelstellung.

Das ist ja alles schön und gut, aber der TO hat geschrieben, dass er die 
Mittelstellung erst bei fast 5 kompletten Durchläufen erreicht (nicht 
4). Und das sind eben 2µS.

> Um das auszuschließen, werde ich heute Abend aber nochmal
> die idiotensichere Variante mit _delay_us() probieren.

Ja, mach das mal. Ich merke gerade, dass ich fälschlicherweise sleep() 
geschrieben habe. Normalerweise programmiere ich PC's daher kommt das 
wohl. Gut das du trotzdem verstanden hast, was ich meinte.

Idiotensicher ist das allerdings nicht. Manche Leute compilieren mit 
-O0, damit man besser debuggen kann. Und dann stimmen die Timings wieder 
nicht. Vermutlich ist Dir das schon bewusst.
Gast #4714512
Lesenswert?

Hugo schrieb:
> Leider habe ich kein Oszi hier...

Es ist doch bald Weihnachten.

Für solche digitalen Fragestellungen reicht meist schon ein 
minimalistischer Logikanalysator. In der Bucht kosten die Dinger 
mittlerweile keine 8€ mehr.

Gönn' dir mal was praktischen.
Gast #4714523
Lesenswert?

Hugo schrieb:
> Leider habe ich kein Oszi hier...

Hast du vielleicht ein Multimeter, das auch Frequenzen messen kann?

Mit dem kannst du die Periode deines PWM-Signals bestimmen. Und dann 
kannst du in der DC-Einstellung die (mittlere) Spannung messen. Deren 
Wert entspricht VDD*Pulsbreite/Pulsperiode

Ist zwar nicht ultrapräzise, aber für den 25% Unterschied von 1,5ms zu 
2ms reicht es vielleicht.
Gast #4714589
Lesenswert?

Hugo schrieb:
> Der Timer zählt also insgesamt 5*256-30 = 1250 Mal, also 40000 Takte
> (Prescaler 1/32). 40000 Takte sind bei 20 MHz aber 2000 µs und nicht
> 1500 µs
Natürlich sind 40.000 Takte bei 20MHz 2ms, wer hätte das erwartet?!
40.000 * 50ns = 2ms.

Bei f = 20MHz dauert ein Takt 50ns (1/f).
Du willst 1500µs (1.5ms) haben.

1.5ms/50ns = 30.000 Takte

Wenn du jetzt einen Prescaler von 8 nimmst dann kommst du auf
(14 * 256) - 166 = 3.750 * 8 -> 30.000 Takte -> 1.5ms -> 1500µs

Alle Prescaler außer 1 und 8 ergeben krumme Werte.
1
Prescaler is: [   1]. Result is: 30000.0
2
Prescaler is: [   8]. Result is:  3750.0
3
Prescaler is: [  32]. Result is:   937.5
4
Prescaler is: [  64]. Result is:   468.75
5
Prescaler is: [ 128]. Result is:   234.375
6
Prescaler is: [ 256]. Result is:   117.1875
7
Prescaler is: [1024]. Result is:    29.296875

Die Antwort auf deine Frage ist also:
Bei f = 20MHz sind es 30.000 Takte.
Gast #4714774
Lesenswert?

Ich habe durch Vergleiche mit _us_delay(1500); gemerkt, dass 1250 
Timer-Durchläufe nicht so ganz exakt die Mittelstellung ergeben. Es sind 
mehr so 1190 nötig. Vorher konnte ich das ja nur Pi mal Daumen 
abschätzen.
Und jetzt kommt's: (1190-256)*32 ist knapp 30000. Mit anderen Worten: Es 
geht irgendwo ein Überlauf "verloren", der eigentlich noch abgewartet 
werden müsste.
Gast #4714803
Lesenswert?

Also, ich glaube, ich habe die Lösung: Da der Timer ständig im 
Hintergrund läuft und die ISR nur bei Bedarf verwendet wird (nur dann 
ist das TOIE2-Bit gesetzt), starte ich schon mit gesetztem TOV2-Bit. Das 
ja nur bei aktivem Interrupt automatisch gelöscht wird.
Die ISR wird also durch diese Altlast schon direkt nach dem Setzen von 
TIMSK2 aufgerufen. Ich müsste das durch ein TIFR2 = 0; nach dem TCNT2 = 
0; lösen können. Aber das teste ich erst morgen.
Gast #4715341
Lesenswert?

Also, es scheint jetzt zu gehen.

Das Fazit aus diesem Thread lautet (und ist vielleicht für viele andere 
hilfreich): Wenn man Timer-Interrupts "bei Bedarf" aktiviert, für genaue 
Wartezeiten oder auch Zeitmessungen, etc., sollte man die entsprechenden 
Flags auch gleich mit zurücksetzen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren