Forum: Mikrocontroller und Digitale Elektronik Wie viele Takte ergeben 1500 µs?


von Hugo (Gast)


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?

von Stefan F. (Gast)


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.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Geh mal andersrum an die Sache ran. Der Timer läuft in 1/(20E6*32*256) = 
409,6µs einmal durch. 4 komplette Durchläufe sind dann 409,6 * 4 = 
1,638ms - also knapp neben der Mittelstellung.

von Hugo (Gast)


Lesenswert?

Mit einem der anderen Timer lasse ich eine Uhr laufen und auf einem 
Display anzeigen. Keine Probleme dort.

Leider habe ich kein Oszi hier...

Ich habe mittlerweile das Servo in Verdacht.
https://www.pololu.com/file/0J730/HD-6001HB.pdf

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Hugo schrieb:
> Ich habe mittlerweile das Servo in Verdacht.

Eine normale RC Fernsteuerung zum Testen nicht vorhanden? Und weil das 
Thema gerade so aktuell ist, es kann bei dir nicht sein, das dein AVR so 
mit ISRs vollgestopft ist, das Timer2 nur selten zum Zug kommt?

von Hugo (Gast)


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?

von Stefan F. (Gast)


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.

von Wolfgang (Gast)


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.

von Achim S. (Gast)


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.

von Kaj (Gast)


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.

von Thomas (kosmos)


Lesenswert?

Wenn man es ganz ohne Messgerät machen möchte setzt man im AVR-Studio 2 
Breakpoints beim ersten setzt man den Counter auf 0 und beim zweiten 
liest man die Takte oder die Stoppuhr ab.

von Hugo (Gast)


Lesenswert?

Oh Wunder: Mit _us_delay(1500); fährt das Servo in die Mittelposition... 
Bin gerade etwas ratlos.

von Hugo (Gast)


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.

von Hugo (Gast)


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.

von chris (Gast)


Lesenswert?

Hugo schrieb:
> TIFR2 = 0

Nein, Interrupt Flags werden durch Beschreiben mit einer '1' gelöscht.

von Hugo (Gast)


Lesenswert?

Also so. Das müsste dann auch die Mittelstellung sein:
1
Overflows = 4;
2
TCNT2 = 86;
3
TIFR2 = 0;
4
HI(PIN_SERVO);
5
TIMSK2 = _BV(TOIE2);

von Hugo (Gast)


Lesenswert?

TIFR2 = _BV(TOV2);

;)

von Hugo (Gast)


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.

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.