Hi,
Ich möchte einen Modellbauservo mit hilfe des "phase correct pwm" modus
des Timer1 eines Atmega 32 ansteuern. Um den Timer zum Laufen zu
bekommen hab ich das Programm ganz einfach gemacht und den Top
Wert(ICR1) so wie den Vergleichswert (OCR1A) fest eingestellt. Wenn ich
alles richtig gemacht hab sollte ICR1 den Wert 20000 haben und OCR1A den
Wert 18500. Das ergibt bei einem Vorteiler von 8 und dem invertierenden
Modus eine Frequenz von 50Hz und eine Pulsweite von 1,5ms. Wie gesagt
wenn ich alles richtig gerechnet habe. Hier mal der Programmcode:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
ISR(TIMER1_COMPA_vect) {
}
int main(void) {
DDRC = 0b1111111;
DDRD = 0b1111111;
DDRB = 0b1111111;
TCCR1A |= (1<<COM1A0)|(1<<COM1A1)|(1<<WGM11);
TCCR1B |= (1<<WGM13)|(1<<CS11);
TIMSK |= (1<<OCIE1A);
ICR1L = 0b00100000;
ICR1H = 0b01001110;
OCR1AL = 0b01000100;
OCR1AH = 0b01001000;
sei();
while(1) {
}
}
Das Problem ist jetzt am Pin 5 von PortD (OC1A) wird nichts ausgegeben.
Und die ISR wird auch nicht ausgeführt. Wäre schön wenn ihr mir helfen
könntet.
Danke schon mal im Voraus.
terminator schrieb:> Hi,>> Ich möchte einen Modellbauservo mit hilfe des "phase correct pwm" modus> des Timer1 eines Atmega 32 ansteuern. Um den Timer zum Laufen zu> bekommen hab ich das Programm ganz einfach gemacht und den Top> Wert(ICR1) so wie den Vergleichswert (OCR1A) fest eingestellt. Wenn ich> alles richtig gemacht hab sollte ICR1 den Wert 20000 haben und OCR1A den> Wert 18500.
Siehs dir halt mal im Simulator an, welche Werte da tatsächlich
zugewiesen werden.
Mir wäre das ja zu blöd, es so zu schreiben
> ICR1L = 0b00100000;> ICR1H = 0b01001110;> OCR1AL = 0b01000100;> OCR1AH = 0b01001000;
Ich würde da ganz einfach schreiben
ICR1 = 20000;
OCR1A = 18500;
und den COmpiler seinen Job machen lassen. Selbst auf die Gefahr hin,
dass der Code dann zumindest ein bischen besser lesbar und
selbsterklärend werden würde.
PS:Wozu braucht man für ein Servo eine 'Phase correct PWM' und einen
invertiert angesteuerten Pin?
Erst mal danke für die schnelle Antwort. Ok das man da direkt den Wert
20000 hin schreiben kann wusste ich nicht. Werd ich gleich mal
probieren. Phase Corect PWM nehm deshalb weil die fast pwm viel zu
schnell ist.
Falls sonst alles korrekt ist, bist du auf einen bekannten Fehler
hereingefallen. Bei 16bit-Registern: erst high-Register, dann
low-Register schreiben. Die Reihenfolge ist zwingend nötig.
Und wenn du das dem Compiler überlässt (siehe Karl-Heinz) bekommst du
gar nicht erst die Möglichkeit, es falsch zu machen :-)
Ich hab des jetzt so gemacht wie es der Karl Heinz geschrieben hat.
Also die Werte direkt rein geschrieben (ICR1=20000) und des
funktioniert. Der Servo fährt dann genau auf die Mittelposition so wie
ichs berechnet hatte. Das heißt des Problem is gelöst.^^
Jetzt muss ich nur noch des Fahren in mehrere Zwischenschritte
unterteilen, damit der Servo langsam fährt. Das war des Ziel der ganzen
Sache. Weil mit Software PWM kann die Schritte net klein genug machen,
damit der Servo ruckelfrei fährt. Denn Sonst wird die ISR zu oft
ausgeführt und das Programm zu sehr belastet.
Also nochmal Dnake für eure schnelle Hilfe.
OK
Mit der ISR bist du da eh schon auf einem guten Weg.
Einfach in der ISR den OCR Wert in Schritten einer Vorgabe nachführen.
1
#define STEP 2
2
3
volatileuint16_tservoSoll;
4
5
ISR(...)
6
{
7
if(OCR1A<servoSoll)
8
{
9
if(OCR1A>servoSoll-STEP)
10
OCR1A=servoSoll;
11
else
12
OCR1A+=STEP;
13
}
14
15
elseif(OCR1A>servoSoll)
16
{
17
if(OCR1A<servoSoll+STEP)
18
OCR1A=servoSoll;
19
else
20
OCR1A-=STEP;
21
}
22
}
WEnn du servoSoll einen Wert zuweist, fährt die ISR das Servo langsam
und in kleinen Schritten an diese Position heran. Mit STEP legst du die
Geschwindigkeit fest - je größer der Wert, desto schneller fährt das
Servo.
Also hab des ganze jetzt mal so geschrieben:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
short i=0;
ISR(TIMER1_COMPA_vect) {
i++;
if((i==1)&&(!(PINA &(1<<PINA0)))) { //nach rechts fahren
OCR1A--;;
}
if((i==1)&&(!(PINA &(1<<PINA1)))) { //nach links fahren
OCR1A++;
}
if(i==1) {
i=0;
}
}
int main(void) {
DDRC = 0b1111111;
DDRD = 0b1111111;
DDRB = 0b1111111;
DDRA = 0b0000000;
PORTC = 0xFF;
TCCR1A |= (1<<COM1A0)|(1<<COM1A1)|(1<<WGM11);
TCCR1B |= (1<<WGM13)|(1<<CS11);
TIMSK |= (1<<OCIE1A);
ICR1=10000;
OCR1A=9450-1;
sei();
while(1) {
if(!(PINA &(1<<PINA0))) {
PORTC &=~ (1<<PB0);
}
if(PINA &(1<<PINA0)) {
PORTC |= (1<<PB0);
}
if(!(PINA &(1<<PINA1))) {
PORTC &=~ (1<<PB1);
}
if(PINA &(1<<PINA1)) {
PORTC |= (1<<PB1);
}
}
}
Zum Testen hab ich mal Taster eingebaut. Ein Taster für jede Richtung.
Der Servo fährt wunderschön. Kann den jetzt richtig langsam fahrn lassen
ohne das man ein Ruckeln sieht. Wenn man jetzt noch bedenkt das des
durch die Hardware PWM kaum das Programm belastet.^^
Die ISR wird aber nicht oft genug ausgeführt. Das heißt ich kann den
Servo mit dieser Ansteuerung nicht schnell fahren lassen. Im Momment
bestimmt die Variable 'i' wie oft die ISR durchlaufen werden muss bis
das nächste mal das OCR1A Register erhöht wird. 'i' kann aber nicht
kleiner sein als 1, also habe ich mir überlegt den mit dem Timer0 per
CTC Modus einen Takt zu erzeugen mit dem dann immer das OCR1A Register
erhöht wird. Ist das eine gute idee oder gibt es da noch eine bessere
Lösung?
terminator schrieb:> Achso stimmt daran hab ich gar nimme dran gedacht das ich au die> Schrittgröße verändern kann. Ok danke für den Hinweis Hans.
Aber schau dir meinen Code nochmal genau an!
Denn im Endeffekt wirst du ja nicht solange fahren wollen, wie du die
Taste drückst, sondern du wirst ja wahrscheinlich mit dem Taster eine
der beiden Endpositionen vorgeben, in die das Servo fahren soll.
Und wenn du die SChrittweite so wählst, dass die Endposition kein
entsprechendes Vielfaches davon ist, dann wird dein Servo entweder
* die Endposition verpassen und weiter fahren
* oder darüber hinausschiessen
Hmm. Von der Tastenabfrage in der ISR bin ich ehrlich gesagt nicht
begeistert. Kommt drauf an, was du machen willst, aber für meinen
Geschmack ist da ein Zusammenhang in der ISR fix codiert, den ich dort
nicht haben will. Die ISR sollte meiner Meinung nach eine Servoposition
anfahren. WO auch immer die her kommt. Zb indem man einen Taster drückt.
Aber auch, weil zb bei einem FLugzeug Einziehfahrwerk der Akku langsam
zur Neige geht und die Elektronik als eine Art 'Achtung' das Fahrwerk
ausfährt. D.h. es mag im Programm viele Stellen geben, die eine
bestimmte Servoposition vorgeben. Welche das sind hat aber die ISR nicht
zu interessieren. Die hat die Vorgabe das Servo an eine bestimmte
Position zu fahren. Nicht mehr und nicht weniger. Wo die Position her
kommt, wie die zustande kommt, hat die ISR nicht zu interessieren.
Ja klar möchte ich im fertigen Programm nicht solange fahren wie ich
einen Taster gedrückt halte. Das ist ja nur ein einfaches Programm um
die Servo Ansteuerung zu testen.
Das soll irgendwann mal wenn es eben so weit fertig ist einen Hexapod
steuern (mit 18 Modellbauservos). Denn bisher läuft der Hexapod mit
einem Atmega32. Dieser erzeugt mithilfe des Timer0 die 18 Servosignale
Software mäßig(CTC-Modus). Jetzt möchte ich aber das Projekt erweitern
und dazu will ich die Servos wahlweise schnell und langsam fahrn lassen
können und auch die Position über den internen Potti der Servos abfragen
können(über ADC). Bisher kann ich die Servos in 0,1ms Schritten
anteuern. Das sind natürlich viel zu große Schritte um den Servo
anständig langsam fahren zu lassen. Also habe ich mir überlegt ein
Bussystem aufzubauen. Mit 6 atmega8 als Slave und jeder bekommt jeweils
3 Servos zum ansteuern. Als Master nehm ich einen Atmega16/32 der dann
den Slaves immer die positionen für die Servos schickt. Dann muss ein
Chip nicht wie vorher die Signale für 18 Servos sondern nur noch für 3
Servos erzeugen. Ein weiterer Vorteil des Bussytems ist das ich durch
die Slaves viel mehr ADC Pins habe. Das Problem ist dann gleich gelöst.
Meine aktuelle Planung war diese 6 atmega8 ihre drei Servos mit Soft PWM
ansteuern zu lassen. Da das aber immer noch ein bisschen ruckelt, trotz
einer Ansteuerung in 0,01ms Schritten, beim langsam fahren möchte ich
doch auf die Hardware PWM umsteigen.
Problem hierbei ist allerdings das der atmega8 nur zwei Pins besitzt,
die mit dem Timer1 also sprich mit einem 16bit verbunden sind
(8 bit Timer reicht nicht von der Auflösung). Das heißt im Endeffekt
mehr Aufwand. Denn ich brauch anstatt 6 chip jetzt 9 (2 Servos pro
chip). Das heist dann auch mehr Platinen und mehr Arbeit und mehr Geld.
Darum wollte ich nun prüfen ob es sich lohnt auf die Hardware PWM
umzusteigen.
Vielleicht habt ihr noch ein paar Ideen wie ich das lösen könnte. Hab
mir schon überlegt anstatt ein atmega8 ein atmega1284p als Slave zu
verwenden. Dieser Besitzt 4Pins die mit einem 16bit Timer verbunden
sind. Der kostet aber beim pollin 6€ das Stück.
Hoffe das ich euch nicht zu sehr zu getextet hab und das mein Problem
verständlich ist. Danke schon mal im voraus.
> Als Master nehm ich einen Atmega16/32 der dann den Slaves immer> die positionen für die Servos schickt. Dann muss ein Chip nicht> wie vorher die Signale für 18 Servos sondern nur noch für 3> Servos erzeugen
Den Teil versteh ich nicht.
Der eine Mega32 langweilt sich mit der Erzeugung der 18 Servosignale.
Und wozu musst der die Position wissen? Der gibt die Position vor! Und
in dem Tempo wie der die Positionen vorgibt, so schnell bzw. langsam
fahren dann auch die Servos.
> Da das aber immer noch ein bisschen ruckelt, trotz einer Ansteuerung> in 0,01ms Schritten, beim langsam fahren möchte ich doch auf die> Hardware PWM umsteigen.
Das ist völlig wurscht, denn mehr als 50 mal in der Sekunde kriegt ein
Servo keinen Positionsupdate. Da kannst du in noch so feinen
Zeitschritten rechnen, das ändert nichts daran, dass von einem
Servoupdate zum nächsten ca. 20ms vergehen. Zeitlich kannst du diesen
Update nicht feiner auflösen. Wenn, dann musst du daran arbeiten, dass
du mehr 'Stufen' in jedem Puls bekommst. Aber das kannst du mit Software
Erzeugung genausogut machen, wie in Hardware. Das schenkt sich nichts.
Beim Beispiel auf
Modellbauservo Ansteuerung
sind es nur deswegen wenig Stufen, weil da der Timer 2 (ein 8 Bit Timer)
benutzt wird. Aber das muss ja nicht so bleiben. Mit dem Timer 1 und
einem kleineren Vorteiler kriegst du dann auch mehr verfügbare
Servostellungen pro Servo und dadurch dann auch weniger Verfahrweg wenn
du die jeweilige Servostellung im Programm um +-1 veränderst.
Also hab im Anhang mal des Programm mit der Ansteuerung, die mit 0,1ms
Schritten arbeitet. Eben das Programm mit dem der Hexapod seither
betrieben wird(ohne langsam Fahrt der Servos -> die fahren also immer
Vollgas).
Zu groben Erklärung wie ich in deisem Programm die Signale erzeugt habe:
Also in der ISR wird die Variable i alle 0,1ms erhöt. Bei i=0 werden die
ersten 6 Pins an denen Servos hängen auf high gesetzt und je nach
Position einzeln wieder auf low. Das läuft dann bei den anderen Servos
genauso (die nächsten 6 bei i=25 und die letzten 6 bei i=50) bis i
wieder 0 ist. i wird immer bei 100 wieder auf 0 gesetzt -> das
entspricht 100Hz.
Wenn ich alle auf einmal anteuern würde gehts nicht weil der chip zu
langsam ist(sollte vielleicht erwähnen das der mit 16MHz läuft->also
maximum). Mit zu langsam mein ich bevor alle if Befehle zum rücksetzten
der Pins ausgeführt werden wird i wieder erhöht und der Pin bleibt
solange high bis irgendwann mal zufällig die Zahl erwischt die er zum
rüclsetzen braucht. Also das habe probiert und nur die ersten paar
Servos fahren dann richtig und der Rest macht auser zucken nichts. Jetzt
stell dir mal vor der timer läuft 10mal schneller (0,01ms Schritte).
Die Positionsabfrage der Servos will ich deshalb machen weil irgendwann
soll des Ding sich ja auch Bewegen. Dazu muss bei einer sehr einfachen
Bewegung das Bein angehoben werden, danach nach vorne bewegt werden und
dann wieder abgesetzt werden. Also fang ich an mit Bein anheben. Die
entsprechenden Servos benötigen jetzt aber Zeit diese neue Position
anzufahren. Wie lange braucht er? Oder anderst gefragt wann ist er an
der Soll position angekommen? Sprich wann kann der nächste Servo das
Bein nach vorne Bewegen. Dies soll ja erst geschehen wenn das Bein oben
ist und nicht früher aber auch nicht später. Bisher hab ich das so
gelöst das immer ein Timer Takt den nächsten Schritt eingeleitet hat.
Das ist aber ungenau und mir zu blöd. Vorallem wenn dann noch schnell
langsam fahren dazu kommt. Oder mal komplexere Bewegungen realisiert
werden sollen. Dann komm ich da eigentlich nicht um die Positionsabfrage
rum wenn ich das anständig machen will.
Als nächstes kann ich noch sagen das die Ansteuerung des Servos mit
16bit Timer WESENTLICH ruhiger ist als mit der Soft PWM und 0,001
Schritte. Das liegt wahrscheinlich daran das ich bei so kleinen
Schritten nicht alle 10 oder 20ms ein update mache sondern halt alle
50-100ms.(je nach Geschwindigkeit).
terminator schrieb:> Also hab im Anhang mal des Programm mit der Ansteuerung,
Sieh dir mal in
Modellbauservo Ansteuerung
an, wie man eine derartige Menge an Servosignalen vernünftig erzeugt.
Das in deiner Variante der µC am Anschlag ist, wundert mich nicht
wirklich. Und das du mit 100 Verfahrpositionen pro Servo keinen
Blumentopf gewinnen wirst, ist mir auch klar.
Das Prinzip aus dem Link auf den Timer 1 bei einem kleinern Vorteiler
übertragen (damit der mögliche 16 Bit Zahlenraum besser ausgenutzt wird)
und du kannst deine Servos so feinfühlig und langsam fahren wie du
willst.
OK. Also ich muss ehrlich sagen das ich das Programm nicht so ganz
verstehe, weil die alles mit so blöden #define dingern da machen. Dann
muss man immer schauen was des jetzt bedeuten soll. Wie funktioniert da
genau die Signal Erzeugung. Vielleicht könnstest du mir das mal erklären
oder einen stark vereinfachten Programm code für einen Servo schicken
ohne die ganze #define Befehle.
....Achso. Also wenn ich das richtig verstehe machen die des so das die
ein Pin von einem Servo auf high setzen und dann den Timer so einstellen
das die interrupt routine nach der gewünschten Zeit für die Position
also z.b. 1,5ms (für Mittelposition) wieder ausgeführt wird. Und dann
wird der Pin gelöscht. Richtig?
Das is ja ne geile Idee. Gefällt mir richtig gut. Aber an den Bus werd
ich trotzdem nicht vorbei kommen wegen der Positionsabfrage. Aber das
macht ja auch nichts das war ja icht das Problem.
terminator schrieb:> ....Achso. Also wenn ich das richtig verstehe machen die des so das die> ein Pin von einem Servo auf high setzen und dann den Timer so einstellen> das die interrupt routine nach der gewünschten Zeit für die Position> also z.b. 1,5ms (für Mittelposition) wieder ausgeführt wird. Und dann> wird der Pin gelöscht. Richtig?
Richtig.
Und dann kommt der nächste Pin drann.
Immer reihum.
Ganz einfach. Und da der Timer die ganze 'Zeitarbeit' macht, hat die CPU
praktisch damit nichts zu tun. Das bischen Pinwackeln alle
(durchschnittlich) 1.5ms kostet praktisch so gut wie keine Rechenzeit.
Jetzt hätt ich aber doch noch ein Bedenken und zwar wenn ich jetzt
langsam fahren will dann warte ich ja nicht zum Beispiel um von Position
ist (1,0ms)
auf Position soll (2,0ms) zu kommen eine millisekunde sondern ich fahr
ja in kleinen schritten das bedeutet z.b. wie es jetzt beim 16bit
Hardware Timer is 0,0005 ms Schritte. Dann würde ja auch die ISR, wenn
ich es so mach wie auf der Seite von dem Link beschrieben, alle 0,5µs
ausgeführt werden. Versteh ich das richtig so?
Dann hab ich doch wieder das Problem das die ISR viel zu oft ausgeführt
wird und der Chip nebenher nichts mehr anderes tun kann oder nicht?
terminator schrieb:> Jetzt hätt ich aber doch noch ein Bedenken und zwar wenn ich jetzt> langsam fahren will dann warte ich ja nicht zum Beispiel um von Position> ist (1,0ms)> auf Position soll (2,0ms) zu kommen eine millisekunde sondern ich fahr> ja in kleinen schritten das bedeutet z.b. wie es jetzt beim 16bit> Hardware Timer is 0,0005 ms Schritte.
Bitte hör auf an dieser Stelle in Millisekunden-Schritten zu denken!
AUfgrund der Auslegung der Pulserzeugung hast du für den kompletten
Servoweg eine bestimmte Anzahl an Schritten verfügbar. Beim Beispiel im
Link sind das so was um die 100 Schritte. D.h. mehr als 100 verschiedene
POsitionen kann das Servo nicht anfahren. Das liegt aber am Timer 2 und
daran, dass das nur ein 8 Bit Timer ist.
Wenn du das auf den Timer 1 umstellst, kannst du aber weit mehr mögliche
Servopositionen erreichen. Sagen wir mal 2000. D.h. du kannst den Weg
von ganz links bis ganz rechts in 2000 Zwischenpositionen zerlegen. Und
so ca. alle 15 Millisekunden kannst du einen anderen dieser 2000
Zwischenschritte an das Servo ausgeben lassen. Das kann von ganz links
nach ganz rechts sein, das kann aber auch von einer Position zur
unmittelbar benachbarten Servoposition sein. Und bei 2000 möglichen
Servopositionen für den kompletten Verfahrweg, liegen 2 benachbarte
Servopositionen so dicht beisammen, dass ich ehrlich gesagt meine
Zweifel habe, ob das Servo das überhaupt genau genug realisieren kann.
> Dann würde ja auch die ISR, wenn> ich es so mach wie auf der Seite von dem Link beschrieben, alle 0,5µs> ausgeführt werden. Versteh ich das richtig so?
Nein, das verstehst du falsch.
Denn das Timing ist dir vom Servo aufs Auge gedrückt. Das kannst du
nicht ändern.
Was dir frei steht ist, wie schnell und welche Zahlenwerte in die
Servo-Variablen geschrieben werden. Aber schneller als ca 15ms da neue
Werte reinzuschreiben ist sinnloss, weil es von einem mal ans Servo
Übertragen bis zum nächsten mal an dasselbe Servo Übertragen eben diese
ca 15ms dauert. Und diese Zeit kannst du nicht ändern! Servos sind zwar
meistens nicht besonder heikel, was ihre Updatefrequenz angeht, aber
weniger als 10ms geht meistens nicht.
Das was der Timer mit den Pins anstellt und welches Timing er
realisiert, hat nichts mehr damit zu tun, in welchen Zeitabständen du
neue Servopositionen an die Servos gibt. Sieh diesen Timer als Black Box
an. Du schreibst deine gewünschten Positionen auf die Variablen und die
Servos fahren in diese Position. Aus. Ende. Diese Variablen mit den
Werten die du reinschreiben kannst, SIND deine Servos. Der Mechanismus,
wie die pyhsikalischen Servos dann ihre Sollposition mitgeteilt bekommen
hat dich nicht mehr zu inetressieren. Das geschieht 'magisch'. (OK, wir
wissen, das das nicht magisch passiert, sondern das der Timer mit ein
wenig ISR Unterstützung das erledigt. Aber für darüberliegende
Softwareschichten ist das 'magisch', weil sie damit nichts zu tun haben.
Die liefern ihre Erkentnisse in Form von Werten in diesen Variablen ab
und mehr braucht sie nicht zu interessieren)
Und wenn du langsam fahren willst, dann stellst du eben nach einem
Zeitschema sukzessive Zwischenpositionen in diese Variablen. Und damit
auch nichts ruckelt, brauchst du genügend mögliche Zwischenpositionen.
Natürlich stimmt. War ein Denkfehler von mir. Die Schrittgröße wird ja
auf die Ist Position des Servos drauf addiert. Dann wäre also bei meinen
Servos der kürzeste Zeitraum von ISR Aufruf bis zum nächsten ISR Aufruf
0,6ms(ganz links)+"die schrittgröße(z.b. 0,5µs)" und nicht wie ich
vorhin gedacht hab nur die Schrittgröße allein.
Und wenn ich in meinem Hexapod Projekt nur drei Servos pro chip zum
ansteuerun hab, bau ich mir einfach einen "Leerlauf"(also ich mein ein
Zeitraum in dem nichts angesteuert wird) ein, damit die Frequenz nicht
zu hoch wird; oder meinst du das macht den servos nichts aus?
Dann kann der chip das ganze sogar so berechnen, dass die Frequenz immer
die gleiche ist und abhänig von den einzelnen Impulslängen der Servos.
Wenn das jetzt so funktioniert wie ich mir das im Momment vorstell und
überlegt hab dann ist richtig gut.
Vielen Dank Karl Heinz. Das hat mir sehr geholfen, denn ich glaub ich
wäre mit den beiden Methoden(1.meine HW PWM, die zu viel Chips
gebraucht hätte und 2. meine schlechte eigene Soft PWM -> sollte ich
vielleicht auch noch dazu sagen das diese Programm vor einem Jahr
entstanden ist, kurz nachdem ich mit C Programmierung und
Mikrocontroller Programmierung begonnen hatte), die ich mir zu Beginn
überlegt hatte nicht besonders glücklich geworden.
So. Hab jetzt mal ein Testprogramm geschrieben. Die Anteuerung
funktioniert genauso wie in dem Link beschrieben ist. Nur hab ich noch
etwas eingefügt das die Frequenz immer gleich halten soll. Weil sie ja
sonst von den einzelnen Impulsen abhängt. Das macht zwar den Servos
nichts aus aber wenn ich den Servo langsam fahren lasse, also jedesmal
wenn die ISR ausgeführt die Positions variable erhöhe dann wird der
Servo je näher er seinem Ziel kommt immer langsamer. Weil ja durch die
längeren Impulse auch die Zeit zwischen den ISR Aufrufen erhöht wird und
damit auch das Positions Update. Allerdings funktioniert das Programm
nicht so wirklich.
Also die Überlegung ist sobald alle 8 Servo Signale einmal ausgegeben
sind soll der Timer1 abgeschalten werden und der Timer0 die restliche
bis 20ms (für 50Hz) so zu sagen füllen oder überbrücken. Also z.B. wenn
jetzt alle Signale für die 8 Servos 1,5ms betragen, dauert es ja 12ms
dann würde es wieder von vorne beginnen. Dann hätte ich aber eine
Frequenz von über 50Hz. Jetzt kommt der Timer0 ins spiel. Der soll nach
der letzten Signalausgabe gestartet werden und in diesem Falle 8ms
laufen. In dieser Zeit soll dann kein Servo Singal ausgegeben werden.
Wenn dann nach den 8ms der Timer1 wieder von vorne beginnt mit der
Ausgabe der Signale habe ich genau die 50Hz.
Schaut euch mal das Programm an, vielleicht habt ihr ja noch andere
Verbesserungsvorschläge oder findet noch mehr Fehler. Danke schon mal im
Voraus.
Du kannst natürlich ein fiktives 9. Servo einführen, welches die Zeit
aufbraucht, um einen kompletten 9-Servo Zyklus auf 20ms zu bringen.
Würd ich allerdings nicht unbedingt tun. Denn wie du schon sagst, den
Servos ist das egal.
Mein Ansatz wäre, den Timer 1 Timer 1 sein zu lassen und den in Ruhe
seine Servosignale erzeugen zu lassen. Weitergehende andere Timings,
greifen dann nicht mehr auf den Timer 1 zurück sondern benutzen eben
einen anderen Timer, der sein regelmässiges Taktsignal als
Basis-Zeittakt erzeugt. Der Timer 0 und der Timer 2 sind ja noch übrig.
Kein Mensch sagt, dass der Timer 1 das komplette Timing des Programms im
Alleingang erledigen muss.
Timer 1 macht die Servopulse
Timer 0 ist unter anderem dafür zuständig, dass die Servopositionen
regelmässig korrekt und in der richtigen Geschwindigkeiten an die
jeweilige Zielpositionen nachgeführt werden.
Aber was du auch tust: Derartige 'Inter-Timer' Lösungen sind oft viel zu
kompliziert und funktionieren auch oft nicht besonders gut. Timer möchte
man durchlaufen lassen. D.h. der wird einmal gestartet und danach läuft
er. Und läuft und läuft und läuft.
Karl Heinz mal wieder Danke für die schnelle Antwort. Aber ich versteh
nicht ganz wie du das meinst. Timer1 macht die Pulse für die Servos und
Timer 0 ist unter anderem dafür zuständig, dass die Servopositionen
regelmässig korrekt und in der richtigen Geschwindigkeiten an die
jeweilige Zielpositionen nachgeführt werden. Könntest du mir das
vielleicht ein bisschen genauer erklären?
anstatt an servo_position[i] weist du die Ziel Position des Servos an
goal_position[i] zu. Der Wert in stepSize[i] bestimmt wie schnell das
Servo fahren soll. Er gibt an, um wieviel sich der Servo Positions Wert
von einem ISR aufruf zum nächsten verändern kann. Wird diese ISR also
alle 1ms aufgerufen, dann ist der Wert genau 1/1000 des Verfahrwegs in 1
Sekunde. Die 1 Millisekunde ist aber auch nicht Pflicht. Du kannst
selbstverständlich auch andere Zeitschritte benutzen.
(und natürlich wird das Servo nicht jede 1 ms einen Schritt machen. Aber
wenn das Servo innerhalb vom Timer 1 das nächste mal drann ist, macht es
dann den kumulierten Schritt aller 1 Millisekunden Schritte, die seit
dem letzten mal angefallen sind.
Da sich das ganz immer noch im Milli- bzw. Hunderstelsekundenbereich
abspielt, wird da dann trotzdem immer noch nichts ruckeln.
Lass den Timer 1 durchlaufen!
(und tu dir selbst einen Gefallen und vergiss, dass du irgendwann mal
von int und short gehört hast. Deine Datentypen sind
uint8_t, uint16_t, uint32_t
int8_t, int16_t, int32_t
Denn da hast du dann die saubere Kontrolle über die Bitbreiten. Die
stehen direkt im Datentyp, ohne dass man lange überlegen muss, was jetzt
was ist.
uint16_t ... unsigned integer mit 16 Bit
wenn immer möglich, möchtest du uint8_t nehmen. Das ist der Leib und
Magendatentyp vom AVR. Damit gehts am schnellsten. Nicht mit int und
nicht mit short. Mit uint8_t - einem Ganzzahl-Datentyp mit 8 Bit und
ohne Vorzeichen.
)