Dieser Wert wird doch im Testprogramm zum Vergleich der Servowerte
genommen, und die gehen von 0 bis 255.
Es zählt also nach der immer vorhandenene Millisekunde, nicht ab dem
Anfang des Pulses.
SV schrieb:> gibt ja den Wert für 1ms wieder aber was ich nicht verstehe ist warum>> #define CENTER (MILLISEC_BASE/2)>> die Mitte sein soll da das ja dann 0,5ms sein müssten oder ?> und ein Servo braucht doch für seine Mittelstellung 1,5ms !>
In der ISR wird bei der Berechnung des nächsten Compare Wertes noch der
Basiswert für 1 Millisekunde zum Servowert dazugezählt. Aus den 0.5ms
werden wieder 1.5ms.
Dadurch können die Servo-Positionswerte in einem uint8_t gehalten werden
und man braucht
* keine 16 Bit speichern, nur damit man den Zahlenbereich hochtreibt
* beim Reinschreiben von neuen Servoewerten in das Arrays sich nicht um
atomaren Zugriff kümmern.
Ahhh ok soweit verstanden, glaub ich ;-)
wenn ich jetzt aber über den ADC Werte an die verschiedenen Servos geben
will schreibe ich die dann ganz einfach in die "while" schleife unten
also als Beispiel:
...
while {1} {
ServoValue[0] ADCH;
....
oder wie gehe ich da am Besten vor ?
SV schrieb:> oder wie gehe ich da am Besten vor ?
Du benutzt die ADC Routinen aus dem Tutorial.
Die liefern dir den ADC Wert, der im Bereich 0 bis 1023 liegt.
Das kannst du so nicht brauchen. Du brauchst also eine Umrechnung aus
dem Bereich 0 bis 1023 auf den Bereich 0 bis 2*CENTER.
Na wenn der Wert 1023 einem Wert von 2*CENTER entsprechen soll, wieviel
entspricht dann dein Wert 'value', den du vom ACD bekommen hast?
Simpler Dreisatz
1
1023 ...... 2*CENTER
2
value ...... x
3
--------------------------------
4
5
value * 2 * CENTER
6
x = ---------------------
7
1023
Wenn du anstellen von 1023 1024 nimmst, dann divdiert sich das leichter
(ist nur Bitschieben). Also
1
value * 2 * CENTER
2
x = -------------------------
3
1024
da kann man jetzt gleich mal die 2 wegkürzen
1
value * CENTER
2
x = ----------------
3
512
jetzt muss man noch darauf achten, dass der Ausdruck im Zähler nicht
größer als 65536 wird. Kann das passieren?
Angenommen CENTER ergibt 64 und value hat als Maximalwert vom ADC 1023
(größer kann der nicht werden), dann sind wir da knapp an der Grenze
drann. Wenn sich für CENTER ein Wert von 67 ergibt, dann sind wir schon
über der Grenze.
So schlimm ist das aber nicht. Man kann zb den Wert für value durch 4
dividieren und dafür den Nenner durch 4 dividieren, dann kommt
mathematisch wieder alles richtig raus.
1
value / 4 * CENTER
2
x = ----------------------
3
128
und jetzt haben wir die Gewissheit, dass der Ausdruck im Zähler nicht
größer als 65536 werden wird, weil value/4 nicht größer als 256 wird und
CENTER per Definition schon mal nicht größer als 128 werden kann.
Ergo programmieren wir
1
.....
2
3
intmain()
4
{
5
.....
6
7
ADC_init();
8
9
10
while(1){
11
12
ServoPuls[0]=ADC_read(0)/4*CENTER/128;
13
14
}
15
}
Gut man könnte das jetzt auch ein wenig effizienter programmieren, weil
es relativ sinnfrei ist, erst vom ADC ein 10 Bit Ergebnis zu holen, nur
um dann erst mal die 2 untersten Bit wegzuwerfen. Allerdings ist das so
(erst mal) alles andere als zeitkritisch, so dass wir uns die paar
zusätzlichen Prozessortakte durchaus erlauben dürfen.
Aber es steht dir natürlich frei, die ADC Routinen entsprechend mittels
ADLAR anzupassen und dann die Berechnung nochmal neu zu überarbeiten.
Ist doch nicht kompliziert :-)
Wenn man weiß wies geht, ist das eine Sache von 4 Minuten ab Starten des
AVR-Studios :-) (und die 4 Minuten mein ich ernst, 5 Minuten klingt so
kitschig. Aber recht viel mehr als Copy/Paste und eine Formel am Papier
vorbereiten ist das nicht)
Edit: Ich weiß schon, dass dir als Assemblerspezi diese Vorgehensweise
ein Greul ist :-) Aber das musst du zugeben: Entwicklungszeitmässig
kommst du da nicht mit. Mit allem nötigen Respekt vor deinen nicht
gerade geringen Assemblerfähigkeiten.
Problematisch sind jetzt nur noch kleine Werte.
Denn durch die Ganzzahldivision kommt leider oft 0 raus und da es eine
Multiplikation ist, ist alles 0. Also Value muss mal sicher 128 betragen
damit da was ordentliches raus kommt.
Oder übersehe ich was?
Ich hab mich schon immer gefragt wie man dieses Problem ordentlich
umgeht, da ich des öfteren schon davor stand^^.
Edit: Ich glaub ich habe meinen Blödsinn gefunden. Es wird zuerst *Value
gerechnet und dann erst dividiert oder? :)
Julian Schild schrieb:> Oder übersehe ich was?
die Multiplikation mit einem Wert in der Größenordnung von ca 64 (das
CENTER) vor der Division.
Der begrenzende Faktor ist nicht das Poti oder der ADC, sonder die
Abstufung der PWM, die sich durch Taktfrequenz und Vorteiler bestimmt.
Je besser er damit bei seiner Taktfrequenz die Obergrenze von 127
trifft, umso mehr Servopositionen kann er anfahren. 127 Servopositionen
hören sich erst mal nicht so prickelnd an, das relativiert sich aber in
der Praxis. (Man könnte natürlich auch alles auf den 16-Bit Timer
umbauen. Das Prinzip ist das gleiche)
Allenfalls könnte man noch eine Rundung einbauen, aber ich bezweifle,
dass er sein Poti so genau einstellen kann, dass sich das bemerkbar
macht.
Julian Schild schrieb:> Problematisch sind jetzt nur noch kleine Werte.
Das ist nicht problematischer als bei den großen Werten, da sowohl ADC
als auch Servo linear arbeiten.
Welche Genauigkeit schafft denn die Servo-Mechanik? Es nützt nichts,
wenn die Ansteuerung wesentlich feiner ist.
Also hab das jetz mal so alles umgesetzt der Servo bewegt sich,
aber in ziemlich großen deutlich sichtbaren Schritten kann man da noch
etwas verbessern ?
SV schrieb:> Also hab das jetz mal so alles umgesetzt der Servo bewegt sich,> aber in ziemlich großen deutlich sichtbaren Schritten kann man da noch> etwas verbessern ?
welche Taktfrequenz hast du? Welchen Vorteiler hast du genommen?
Du willst die beiden Werte so aneinander anpassen, dass der Ausdruck
1
F_CPU/PRESCALER/1000
einen Wert möglichst nahe an 128 ergibt, aber auch nicht größer als 128
wird. Wenn das nicht vernünftig möglich ist, dann könnt man auf den
Timer 1 ausweichen. Der ist ein 16 Bit Timer und dementsprechend kann
man dann die Abstufung feiner machen um mit dem zur Verfügung stehenden
Timer-Zählbereich die 2ms abzudecken. Mit dem 8-Bit Timer stehen nun mal
nur 256 Abstufungen dafür zur Verfügung, von denen 128 für die
Basis-Millisekunde drauf gehen und somit nur 128 Servopositionen (die
restliche Millisekunde auf 2ms) übrig bleiben.
Edit: Du musst natürlich dann auch die Bits für den Vorteiler
entsprechend anpassen. Siehe Datenblatt.
SV schrieb:> Habe 1 Mhz, Vorteiler 128,> da eigentlich nur beschrieben ist das ich unter 128 bleiben soll !
Ist richtig.
generell solltest du allerdings Code nicht einfach nur übernehmen,
sondern auch ein wenig durchsehen, was mit den Werten gemacht wird. Und
dann stellt sich schnell raus, dass du mit 1Mhz und 128 einen Wert von
1
1000000 / 128 / 1000 = 7
für 1 Millisekunde bekommst. d.h. 1 Millisekunde wird in 7 Abstufungen
aufgeteilt und demenstprechend hast du auch nur 7 Servopositionen.
Also: Beim übernehmen von Code immer mitdenken. Hirn ausschalten war
gestern, als Mutti noch mit aufs Klo kam. Wer programmieren will, muss
wissen was er tut.
Bei 1Mhz wäre ein Vorteiler von 8 angebracht.
1
1000000 / 8 / 1000 = 125
also schon ganz gut am Maximum drann.
beim Mega16 wäre das
Ahh Ok ! ich versuche seit Nachmittag so n bischen den Code zu verstehen
weil ich das eig generell nicht möchte, Kopieren :-)
aber ich muss mich morgen nochmal ausgeschlafen dahintersetzten :-))
aber das hilft schon mal wieder ein bischen weiter Danke
SV schrieb:> Ahh Ok ! ich versuche seit Nachmittag so n bischen den Code zu verstehen> weil ich das eig generell nicht möchte, Kopieren :-)
Er ist im Grunde sehr sehr simpel.
Die Frage ist: wie weit muss der Zähler zählen, damit er dafür genau die
vorgesehene Zeit braucht.
Damit das aber möglich ist, muss der Vorteiler so eingestellt werden,
dass der Timer möglichst 2ms braucht um von 0 bis 255 zu zählen.
Erreicht er die 2ms schon, wenn er erst bei 240 ist, dann ist das auch
ok. Aber 300 geht nicht, weil der Timer nicht so weit zählen kann.
Muss der Timer also von 0 bis 240 zählen um damit 2ms abzumessen, dann
teilen sich diese 240 so auf
120 für die konstanten 1ms, die obligatorisch sind
weitere 120 für den variablen Teil, der die Servoposition darstellt.
ja nachdem ob zu den konstanten 120 dann noch 0 oder 120
oder ein Wert dazwischen dazukommt, ergibt sich dann
in Summe ein Wert zwischen 120 bis 240. Also Zeiten
zwischen 1 und 2 ms.
Die 120 finden sich im Code als MILLISEC_BASE wieder ("Basis für 1
Millisekunde")
Und es ist auch klar, dass du diesen Wert so hoch wie möglich treiben
willst. Denn wenn der Timer schon bei einem Zählerwert von
beispielsweise 8 bei 2ms angelangt ist, dann hast du nur die Zählerwerte
4, 5, 6, 7 und 8 übrig, mit denen du die variable Zeit von 1
Millisekunde aufteilen kannst. Demenstprechend hast du dann natürlich
aber auch nur diese Servopositionen zur Verfügung. Und 5 Stück
Servopositionen sind dann ein bischen arg wenig.
Und so läuft es dann:
Pin einschalten, Timer läuft los.
Der Timer ist so eingestellt, dass er nach der berechneten Zahl (zb 180
für 1.5ms) einen Interrupt auslöst. Im Interrupt wird der Pin wieder
abgeschaltet und der nächste Pin für das nächste Servo eingeschaltet.
Wieder wird der Timer mit dem diesem Servo zugeordneten Endwert versorgt
und der Timer zählt für sich diese Zeit ab. Udn so gehts immer reihum.
Wird ein Pin abgeschaltet wird sofort der nächste Pin eingeschaltet und
der Timer mit dem diesem Servo zugeordneten Zeitwert (in Form des
Vergleichsewrtes) versorgt. Nach dieser Zeit kommt ein Interrupt und es
wird auf das nächste Servo weitergeschaltet.
Die Pulse für 8 Servos werden also hintereinander generiert und nicht
gleichzeitig nebeneinander.
Edit: die 240 bzw. 120 sind jetzt natürlich nur beispielsweise. Bei dir
kommen da andere Zahlen raus. Abhängig von Taktfrequenz und Vorteiler.
Sag mal Karl Heinz, warst du in einem früheren Leben mal ein
Tibetanischer Schweigemönch oder was muß man kauen, um so eine
Engelsgeduld zu bekommen? Chapeau !
MfG Klaus
Klaus schrieb:> Sag mal Karl Heinz, warst du in einem früheren Leben mal ein> Tibetanischer Schweigemönch oder was muß man kauen, um so eine> Engelsgeduld zu bekommen? Chapeau !>> MfG Klaus
:-))) Ja die hat er mit mir
Respekt
und vorallem sehr nett !