Hallo,
ich habe einen Atmega16 auf einem STK500 (ohne Quarz, daher Nutzung 1MHz
Taktes des µCs) zur Verfügung und möchte 2 Timer verwenden, die in
untersch. Intervallen je ihre Interrupt Routine (ISR) aufrufen.
1. Frage: Kann es in einem Programm mehr als zwei ISRs geben?
2. Frage: Ist ein PWM gesteuerter Timer in Kombination mit dem STK500
genauer als einer ohne PWM, wenn wie oben gesagt nur der µC interne 1MHz
Takt verwendet werden kann?
3. Frage: Jetzt interessiert mich aber noch, ob ich den "8-Bit Timer2
mit PWM und asynch. Operation" genauso verwenden kann wie den "8-Bit
Timer1 mit PWM".
Ich würde mich über jede Hilfe freuen, da ich sowohl zum ersten Mal
einen Timer als auch einen Interrupt verwenden möchte.
twizzler
P.S.: Ja, das Datenblatt zum Atmega16 habe ich zur Hand. Ich würde aber
nicht fragen, wenn ICH meine Probleme allein damit lösen könnte.
OK, ich glaube mittlerweile verstanden zu haben, dass der PWM Betrieb
für meine Anwendung am besten geeignet zu sein scheint. Der 16-Bit Timer
erlaubt ebenfalls einen PWM Mode. Dann nehme ich nun diesen, oder?
Schließlich benötige ich hier kein Prescaling Faktor und kann daher mein
Signal µs genau bestimmen.
was willst du eigentlich genau machen?? du brauchst keine PWM um einen
Timer zu nutzen, die PWM (Pulsweitenmodulation) ist lediglich eine
Funktion, die der Timer zur verfügung stellt....Datenblatt...
Für das was du machen willst reicht ein timer der einen compare match
interrupt auslöst.... unter umständen reicht ein timer, wenn er 2
compare register besitzt. und nun zum prescaler (vorteiler) den kannst
du einsetzen um längere zeiten verwirklichen zu können... ein Beispiel
wenn du einen uC verwendest mit 1MHz Systemtakt 1/1MHz = 1us das heisst
ohne prescaler kannst du mit einem 8Bit Timer (0-255) genau 256us
messen.... der Prescaler macht also schon sinn.... erzähl mal was du
genau machen willst...
@Jan Herzog
Den PWM halte ich für sinnvoll, da ich ein Servo ansteuern möchte. Und
mit dem PWM könnte man ein Rechteck Signal generieren. Und ich denke,
dass ich die Länge des Rechtecks in der main beeinflussen kann, oder?
Den Prescaler brauche ich beim 16 Bit Timer deshalb nicht, weil meine
längste Zeitdauer 20ms - s. Servo - nicht überschreitet, oder?
@Jan Herzog
Die Interrupts habe ich mir für die erste Variante mit den zwei Timern
als scheinbar sinnvoll ausgedacht. Der erste Timer sollte das High Level
Signal an einem beliebigen Portpin einschalten und der zweite Timer
sollte für die verlbeibende Zeitdauer der insg. 20ms den Pin wieder auf
Low setzen. Benötigt für solche Dinge keinen Interrupt?
Erübrigt sich die Interrupt Sache, wenn ich einen PWM verwende?
dafür brauchst du definitiv nicht 2 timer.
wenn du eine periodendauer von 20ms hast und dein high zwischen 0 und
diesen 20ms variiren können soll, nimmst du einen timer den du so
einstellst, dass die periodendauer eben genau 20ms ist, und benutzt im
im compare match mode (oder so ähnlich). dann stellste die ganze
geschichte noch so ein das der output compare pin passend getoggelt
wird, und du musst in deiner main nur das compare register passend
nachladen
Du kannst nur mit Timer 1 arbeiten.
Timer ohne Vorteiler als PWM mit TOP-Wert in
ICR1 (hier 20000 -> 20 ms) und OCRA und B als
PWM-Wert (sinvoll sind beim Servo 1000-2000 -> 1-2 ms)
Pin wird gesetzt PD4 für OCRB PD5 für OCRA.
Mit der Vorlage sollte es gehen.
Eigentlich ja, aber:
Signal 1 ms immer ein, 0-1 ms ein, 18-19 ms aus = 20 ms
Die Info ist die Dauer des Impulses (1-2 ms) bzw. die
Dauer (0-1 ms) nach dem Grundsignal (1 ms).
Die 18-19 ms danach sind uninteresant (aber wichtig).
Wenn ich die 20 ms mit 8 Bit auflöse erhalte ich 78 µs als
Einheit. Der Bereich 0-1 ms der die Info enthält hat dann
nur noch 13 Stufen.
Bei einem Servo mit 180° sollten es aber deutlich mehr sein.
Man muß also Aufteilen in Signal und Verzögerung.
Daher ist der Weg oben mit den 16 Bit eigentlich sehr
genau und einfach.
Für die anderen Wege gibt es hier im Forum viele Beispiele
(Suchfunktion!).
gruß hans
Ich sehe den letzten Beitrag von avr als schlüssig an. Zudem reichen mir
die 8-Bit tatsächlich nicht.
@Spess:
Was meinst du mit "So sollte man es NICHT machen"?
Hi
>Was meinst du mit "So sollte man es NICHT machen"?
Es gibt Bitdefinitionen, die man benutzen sollte:
TCCR1B = 1<<CS12|1<<CS11 ist wesentlich aussagekräftiger als
TCCR1B= 0x6
Hat nichts mit falsch oder richtig zu tun.
MfG Spess
@avr
ich habe gerade deinen Code kompilieren wollen und festgestellt, dass
ich die macros.h nicht habe. Ich habe CLI() durch cli() und SEI durhc
sei() ersetzt und die macros.h durch die interrupt.h ersetzt. Ist das
auch OK? Kompilieren ist so jedenfalls möglich.
Wofür sind die defines?
#define PWM_B 4 //PD4
#define PWM_A 5 //PD5
Muss ich den Servo wirklich an PD4 und PD5 anschließen?
Ich vermute der PWM_B Wert ist für das variable 0...1ms Signal gedacht.
Wie setze ich PWM_B beispielsweise auf 0,5ms; etwa so? PWM_B = 500;
LG twizzler
twizzler schrieb:
> Wofür sind die defines?>> #define PWM_B 4 //PD4> #define PWM_A 5 //PD5>> Muss ich den Servo wirklich an PD4 und PD5 anschließen?>> Ich vermute der PWM_B Wert ist für das variable 0...1ms Signal gedacht.> Wie setze ich PWM_B beispielsweise auf 0,5ms; etwa so? PWM_B = 500;
Nein.
Du weist einen Wert an das OCR1A oder OCR1B Register zu.
Für weitere Details verweise ich auf das Datenblatt zu deinem Prozessor.
Im Kapitel über den Timer 1 findest du auch eine ausführliche
Beschreibung zur PWM, welche Register beteiligt sind und wo die Signale
am µC herausgeführt sind.
> void timer1_init(void)> {> TCCR1B = 0x00; //stop> TCNT1H = 0xB1; //setup> TCNT1L = 0xE1;> OCR1AH = 0x4E;> OCR1AL = 0x1F;> OCR1BH = 0x4E;> OCR1BL = 0x1F;> ICR1H = 0x4E;> ICR1L = 0x1F;> TCCR1A = 0xF2;> TCCR1B = 0x19; //start Timer> }
Na denn, viel Spass beim Aufdröseln in die einzelnen Bits und
identifizieren mit dem Datenblatt, was da eigentlich alles eingestellt
und freigeschaltet ist.
Man kann das ganze auch so schreiben
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1 = 0xB1E1; //setup
OCR1A = 0x4E1F;
OCR1B = 0x4E1F;
ICR1 = 0x4E1F;
TCCR1A = 0xF2;
TCCR1B = 0x19; //start Timer
}
Das hat dann den Vorteil, dass sich der Programmierer nicht um die
korrekte Beschreibung eines 16 Bit Registers kümmern muss, sonder der
Compiler sich um die richtige Reihenfolge kümmert (erst High, dann Low).
Das Aufdröseln der Bits in TCCR1A und TCCR1B hingegen überlass ich dem
Leser :-)
> Die 18-19 ms danach sind uninteresant (aber wichtig).
Nicht wirklich. Den meisten Servos ist das völlig egal, ob da eine 18 ms
Pause hinten nach kommt oder nicht. Servos interessieren sich sowieso
nur für die Länge des Pulses. Die Wiederholzeit von 20ms kommt ja nicht
aus einem Servoproblem an sich, sondern ist entstanden, weil man einige
Servopositionen hintereinander über die Funkstrecke schicken muss und
trotzdem noch erkennen können muss, welcher Puls zu Servo 1 gehört. Am
Funkweg sind einfach nur alle Puls hintereinander angeordnet. Jeder Puls
kann maximal 2 ms lang sein, so dass man bei 8 Servos dafür maximal 16
ms (plus ein paar Zerquetschte) für die 8 Pulse brauchte. Dann noch eine
etwas längere Pause (für den Frameanfang) und fertig war der
Übertragungsframe. Der Empfänger pfriemelt da gar nicht lange rum,
sondern lässt einfach einen Zähler mitlaufen. Mit jedem Pulsende wird
der nächste Puls auf den nächsten Ausgang durchgeschaltet, bei einer
längeren Pause wird der Zähler wieder auf 0 gesetzt. Und so kommt es,
dass an einem Servoausgang am Empfänger nur alle 20ms ein Puls
auftaucht.
Aber wie gesagt: Analogservos ist diese Zeitdauer ziemlich egal.
Lediglich Digitalservos werten diese Wiederholrate manchmal aus um zu
erkennen, ob sie vielleicht einem Störsignal nachlaufen, oder ob die
Pulslänge tatsächlich von einem Sender stammen kann.
@Karl Heinz Buchegger
Jetzt bin ich wohl der entdröselmeister! ;-)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1 = 0xB1E1; //setup, 45537 (?)
OCR1A = 0x4E1F; //19999
OCR1B = 0x4E1F; //19999
ICR1 = 0x4E1F; //19999
TCCR1A =
1<<COM1A1|1<<COM1A0|0<<COM1B1|0<<COM1B0|0<<FOC1A|0<<FOC1B|1<<WGM11|0<<WG
M10;
TCCR1B = 0<<ICNC1|0<<ICES1|1<<WGM13|1<<WGM12|0<<CS12|0<<CS11|1<<CS10;
//start Timer
}
Kompilieren funktioniert schon mal. Danke übrigens für deine Antwort
bezüglich der PWM-Wert Änderung. Weißt du zufällig auch warum die o.
angefragten #defines dann noch wichtig sind, obwohl sie nun im Code
nicht mehr vorkommen.
Auch die Antwort auf die Frage, ob die Servos wirklich an beide Pins PD4
u. 5 anzuschließen sind, würde mich noch sehr interessieren.
Das war es erstmal an weiteren Fragen.
Scheinbar habe ich da irgendwelche Verständnisschwierigkeiten. Nach dem
Datenblatt sieht es so als entspräche PD4 oder PD5 dem OCR1A oder OCR1B
Signal. Wobei sich letztere scheinbar nur dadurch unterscheiden, dass
sie invers zueinander sind. So entschied ich mich zunächst für PD4 als
Steuerleitung für mein Servo. Allerdings tat sich da nichts. Wenn ich
eine LED über PD4 ansteuere leuchtet diese aber permanent bzw. mit einem
20ms Takt. Habe leider kein Oszilloskop zur Hand.
Warum zappelt mein Servo nicht? Und wieso beträgt der TCNT Wert 45537
anstatt 20000?
Müssen die Datenblätter so verteufelt undurchsichtig sein?
Bitte gebt mir einen weiteren Hinweis!
twizzler schrieb:
> Scheinbar habe ich da irgendwelche Verständnisschwierigkeiten. Nach dem> Datenblatt sieht es so als entspräche PD4 oder PD5 dem OCR1A oder OCR1B> Signal.
Bingo
> Wobei sich letztere scheinbar nur dadurch unterscheiden, dass> sie invers zueinander sind.
Das sind 2 voneinander unabhängige PWM Einheiten (ok, sie teilen sich
den TOP Wert, da sie beide am gleichen Timer beheimatet sind).
Ich habe jetzt die Konfigurationsbits nicht studiert. Kann natürlich
sein, dass die so eingestellt sind, dass an der einen das inverse der
anderen raus kommt.
> Warum zappelt mein Servo nicht? Und wieso beträgt der TCNT Wert 45537> anstatt 20000?
Als erstes musst du mal ergründen, welcher PWM Modus eingestellt ist.
Was ist der TOP Wert (wie weit zählt der Timer).
Wie schnell taktet dein µC?
Davon ausgehend musst du zurückrechnen, welcher Wertebereich in OCR1A
(bzw. OCR1B) dem Bereich 1 bis 2 ms entspricht.
OK.
WGM13 ist gesetzt, WGM12 und WGM11.
Das ist MOdus 14. In diesem Modus zählt der Timer von 0 bis ICR1. Ist
ICR1 erreicht, wird der Timer auf 0 gesetzt und es geht wieder von vorne
los.
Das vorladen des TCNT1 kannst du ignorieren. Das ist nur beim ersten
Durchlauf interessant und man hätte TCNT1 in diesem konkreten Fall
genausogut einfach auf 0 setzen können. Wird dann der Overflow erreicht
zählt der Timer immer von 0 bis 19999. (65536 - 19999 = 45537)
Mit dieser Belegung:
TCCR1A =
1<<COM1A1|1<<COM1A0|0<<COM1B1|0<<COM1B0|0<<FOC1A|0<<FOC1B|1<<WGM11|0<<WG
M10;
sollte sich eigentlich am B-Kanal gar nichts tun.
COM1A1 und COM1A0 sind so geschaltet, dass
"Set OC1A on compare match, clear OC1A at BOTTOM"
d.h
Der Timer zählt fröhlich vor sich hin. Immer von 0 bis 19999 (weil in
ICR1 19999 drinnen steht).
Wenn der Timerwert (in TCNT1) gleich OCR1A ist, dann wird der Ausgang
OC1A auf high geschaltet. Erreicht dre Timer die 19999, wird er im
nächsten Takt zu 0 und gleichzeitig wird der Ausgang OC1A wieder zu 0.
Wenn du also einen 1 ms Puls haben willst, musst du den OCR1A Wert so
einstellen, dass der Timer noch 1 ms braucht, ehe er 19999 erreicht.
Wenn 19999 tatsächlich 20 ms entsprechen, dann sind 1ms ein Wert von
1000. Du musst OCR1A also auf 18999 stellen. Denn dann braucht der Timer
noch genau 1ms bis der TOP Wert 19999 erreicht wird.
Alternativ kannst du die ganze Schose natürlich umstellen, sodass der
OC1A Pin bei einem Timerwert von 0 auf 1 geht und bei erreichen des
Comparewertes wieder auf 0 fällt.
Das wär dann COM1A1 auf 1, COM1A0 auf 0
OCR1A auf 1500 ergibt dann einen 1.5 ms Puls, der sich alle 20 ms
wiederholt.
Alles bei 1 Mhz gerechnet (ich hab jetzt die Zahlen von avr nicht
nchgerechnet)
@Karl Heinz Buchegger
Vielen Dank für deine sehr ausführlichen Hinweise. Hat mir sehr
weitergeholfen. Ich habe deinen letzten Tip befolgt und die Schose
umgedreht, d. h. COM1A1 auf 1, COM1A0 auf 0
Für's erste komme ich soweit zurecht. Vielen Dank für jede Hilfe von
Euch allen!!!
Ich habe zunächst eine ganz einfache Routine geschrieben:
Servo ganz links, dann 5 Sek. später ganz rechts, dann 5 Sek. später
wieder ganz links usw.
Häufig brummt oder vibriert der Servo beim Verharren an einer Position
oder beim Rüberfahren zur nächsten Position. Manchmal erfolgt das
Verharren oder Rüberfahren auch ohne brummen. Ich kann da keine
Regelmäßigkeit feststellen. Ich habe bisher zwei verschiedenen Servos
unterschiedlicher Bauart getestet. Das Verhalten ist bei beiden
identisch.
Kennt das jemand von Euch?
twizzler schrieb:
> Kennt das jemand von Euch?
Ja.
Das kommt auch bei 'normaler' Benutzung von Servos mit einer
Fernsteuerung vor. Im Servo können billige Potis verbaut sein, bei denen
der Schleifer ein klein wenig hakt und das Poti auf kleine Stellversuche
nicht gleich reagiert und sich der Widerstandswert in kleinen Sprüngen
ändert. Die Folge ist, dass die Servoelektronik ständig am Nachregeln
ist. Es ist nicht unüblich, dass ein Servo an einer Position knurrt und
an einer Position gleich daneben völlig ruhig ist. Auch ein
schwergängiger Kraftabtrieb vom Servo (Bowdenzüge die schwergängig
verlegt sind) kann dieses Phänomen verursachen. Oder ein Servo welches
über die Endstellung gefahren ist sodass die interne Überdrehsicherung
im Getriebe (ein Zapfen) an den Endpositionen in seiner Nut ansteht.
Das ist ja blöd. Dann habe ich für 35 € einen "Billigservo"
(Segelwindenservo) erstanden! Ich werde mal größere Schrittweiten
testen. Wenn aber alles nichts hilft, kann ich nur hoffen, dass er trotz
der großen Regelanstrengung 48 Stunden am Stück durchhält.
Danke für die Antwort!