Guten Tag,
ich möchte euch bitte mein Problem anzuschauen und mir vielleicht
zusagen was ich ändern muss.
Ich habe ein Programm geschrieben welches einen Servo ansteuern soll per
CTC Interrupt. Das ist dabei raus gekommen :
Mein Problem ist das Ich den Servo nur gezielt auf 0 einstellen kann und
sonst die Anderen Positionen nicht. Außerdem zittert der Servo die ganze
Zeit. Ich arbeite unter der Arduino IDE, deshalb Loop und setup statt
main. Mein Mikroprozessor ist ein ATmega 328.
Ich danke jetzt für eure Tipps und wenn ich einfach zu dumm rügt mich
einfach.
MFG Jan
Geh noch mal Schritt für Schritt durch was dieses Konstrukt hier macht !
if(ZaehlerMillisekunden<1000){
StromAn= false;
ZaehlerMillisekunden++;
}
else if(ZaehlerMillisekunden<=1500){ //1500 gibt Winkel an/ sollte
Mittelposition sein
StromAn= true;
ZaehlerMillisekunden++;
}
else if(ZaehlerMillisekunden<2000){
StromAn= false;
ZaehlerMillisekunden++;
}
else{
ZaehlerMillisekunden = 0;
}
1s aus -> 0.5s an -> 0.5s aus -> 1s aus -> 0.5s an -> 0.5s aus -> 1s aus
-> 0.5s an -> 0.5s aus ->
Gibt 0,5Hz mit einem Puls-Pausen-Verhältnis von 3:1
Ist glaube ich nicht gerade das was ein Modellbauservo haben will
if(ZaehlerMillisekunden<=500){ //500 gibt Winkel an/ sollte
Mittelposition sein
StromAn= true;
ZaehlerMillisekunden++;
}
else if(ZaehlerMillisekunden<20000){
StromAn= false;
ZaehlerMillisekunden++;
}
else{
ZaehlerMillisekunden = 0;
}
Ich hab den einen Tippfehler korrigiert danke :) statt 2000 20000 für
den 20 ms Intervall. Außerdem hab ich die erste Pause entfernt.
Trotzdem funktioniert das einstellen immer noch leider nicht.
Die ganze ISR ist nicht logisch.
Ich geh mal davon aus, dass das hier stimmt (ich habs nicht
nachgerechnet)
1
OCR1A=40;// 1us
und du tatsächlich alle 1µs einen Interrupt bekommst. (was mir ehrlich
gesagt ein wenig komisch vorkommt. Bei einem mit 16Mhz getaktetem AVR,
wäre das dann in jedem 16-ten Takt. Das wird sich nie und nimmer
vernünftig ausgehen. Ich würde da auf jeden Fall mal eine Zehnerpotenz
höher gehen)
D.h alle 1µs wird das hier
aufgerufen.
Jetzt benutzt du einen Zähler, mit dem du die µs in die Zeiten bzw.
Zeitpunkte verwandelst, die du für das Servo Signal benötigst.
Du möchtest eine 20ms Wiederholrate des Servosignals haben, also lässt
du deinen Zähler nur bis 20000 laufen, denn das wären 20ms
Damit hast du eine Variable, die Werte von 0 bis 19999 annimmt, wobei
jeder Zahlenwert für eine weitere 1µs Periode steht.
Das Wesen eines Servosignals besteht darin, dass es am Begin der
kompletten 20ms Periode auf 1 geht und dann je nach gewünschtem
Drehwinkel eine gewisse Zeit später wieder auf 0.
Diese gewisse Zeit hat Einschränkungen. Sie ist minimal 1ms und maximal
2ms. Das braucht dich aber momentan nicht wirklich kümmern, denn das ist
ja nur ein Zahlenwert (wenn man die Zeiten in Einheiten dieses timCount
ausdrückt). Ich nenne die Variable, die diese 'Abschaltzeit' beinhaltet
einfach mal servoPos. Wichtig ist, das der Ausgangspin bei Beginn der
20ms Periode auf 1 geht, und nach servoPos Zeiteinheiten wieder auf 0.
Diese Zeitpunkte sind aber leicht zu finden, indem man einfach nur den
entsprechenden Zahlenwert mit dem µs-Zähler vergleicht, der ja alle 20ms
erneut wieder bei 0 startet und jede 1µs um 1 höher wird)
Also:
Fertig. Das wars im Grunde schon.
Wo das Servo stehen soll, wird durch den WErt in servoPos bestimmt.
Weist du dem 1000 zu, dann fährt das Servo nach links. weist du der
Variablen 1500 zu, dann steht das Servo in der Mitte und weist du der
Variablen den Wert 2000 zu, dann fährt das Servo auf Rechtsanschlag.
1
voidsetup()
2
{
3
....
4
5
servoPos=1500;
6
}
7
8
voidloop()
9
{
10
servoPos=1500;
11
delay(10000);
12
13
servoPos=1000;
14
delay(10000);
15
16
servoPos=2000:
17
delay(10000);
18
}
Aber: Am Arduino gibts doch fix&fertige Servo Klassen. Warum benutzt du
die nicht?
Karl Heinz schrieb im Beitrag #3551787:
> Aber: Am Arduino gibts doch fix&fertige Servo Klassen. Warum benutzt du> die nicht?
Ich bin in einem Mikroprozessorprojektkurs. Und wir wollten ein R/C Auto
per Funk ansteuern. Leider überschneiden sich die Klassen VirtualWire
und Servo. Da Ich allgemein Programmierkenntnisse besitze in C++ soll
ich von meinem Lehrer aus versuchen selbst das Problem zu lösen, indem
ich eine Ebene tiefer geh. Und das Versuch ich jetzt zu erlernen. MAcht
auch Spaß ist trotzdem für den Einstieg extrem hart.
Ich kenn das ganze eher so:
Der eine Anschlag -> 0,5ms an -> 19,5ms aus -> 0,5ms an -> 19,5ms usw.
Mitte -> 1ms an -> 19ms aus -> 1ms an -> 19ms usw.
Der andere Anschlag -> 2ms an -> 18ms aus -> 2ms an -> 18ms usw.
Die Gesamtdauer zwischen dem Impulsbeginn ist immer 20ms
Und benenne "ZaehlerMillisekunden" mal in "ZaelherMikroSekunden" um, das
verwirrt doch etwas
Irgendwer schrieb:> Ich kenn das ganze eher so:> Der eine Anschlag -> 0,5ms an -> 19,5ms aus -> 0,5ms an -> 19,5ms usw.> Mitte -> 1ms an -> 19ms aus -> 1ms an -> 19ms usw.> Der andere Anschlag -> 2ms an -> 18ms aus -> 2ms an -> 18ms usw.> Die Gesamtdauer zwischen dem Impulsbeginn ist immer 20ms
Die 20ms sind beim Servoansteuern das unwichtigste überhaupt.
Wichtig ist die Impulsdauer.
Leider gibt es da 2 Definitionen. Die meisten Firmen definieren den Puls
als 1ms - 2ms (mit einer Mitte von 1.5ms). Wobei natürlich nicht
ausgeschlossen ist, dass ein Servo auch noch bei 0.9ms noch sauber
positioniert, oder bei 0.8ms. Ein bischen Reserve ist da immer mit
drinnen, ehe man dann am mechanischen Endanschlag angelangt ist.
Eine einzige Firma, deren Name mit 'Multi' beginnt und mit 'plex' endet,
hat auch noch aus historischen Zeiten andere Pulsdauern im Gebrauch.
Aber auch die sind nicht die von dir angegebenen Zeiten. Wenn mich nicht
alles täuscht, dann sind die M...x Pulsdauern ein bischen kürzer und
laufen von 0.8ms bis ca 1.8ms, mit einer Mittelstellung von 1.3ms. Also
einfach nur die Zeiten ein klein wenig kürzer.
Aber 0.5ms für links, 1ms für mitte und 2ms fpr rechts ist mir noch nie
unter gekommen. Das wäre auch höchst kontraproduktiv und nicht sehr
logisch.
Ach, ich hab ja komplett überlesen
> #define F_CPU 8000000UL
Du fährst mit 8 Mhz.
Wie kommst du dann auf
> OCR1A = 40; // 1us
für 1µs?
Du hast hier nicht 1µs eingestellt, sondern 5µs!
Demenstsprechend stimmen natürlich die Zeiten, respektive die
Zahlenwerte in der ISR bzw. bei den Zuweisungen an servoPos überhaupt
nicht. Alles um den Faktor 5 zu groß
Eigentlich sollte ich es schon wissen, das man Kommentaren nicht trauen
soll. Lieber alles nachrechnen.
Jan Meyer schrieb:> Ich hab damit den CTC Wert ausgerechnet> http://www.bunbury.de/Technik/timerberechnung.htm
Und?
Welche Werte hast du eingesetzt?
Egal was ich dort einsetze, 40 kriege ich nicht als Ergebnis bei 1µs
Lies dir das durch
FAQ: Timer
und rechne dir das selber aus, anstatt irgendwo Zahlen einzusetzen.
Was ist jetzt mit den 8Mhz. Stimmen die?
Ich dachte immer Arduinos laufen mit 16Mhz, was mir auch eine kurze
Web-Recherche bestätigt.
Und nein. Nur um das klar zu stellen.
Du willst keinen CTC MOdus mit einem Compare Wert von 4. Alles unter 100
ist nicht wirklich akzeptabel. Selbst 40 (die eigentlich als 39 im
Programm geschrieben werden müssten), sind schon grenzwertig. Alle 40
Prozessortakte ein Interrupt müllt dir die Maschine zu. Die macht ausser
Interrupts nur noch Interrupts.
Der ganze Ansatz mit einem µs Interrupt ist nicht besonders schlau. Aber
das kann man immer noch ändern. Jetzt ist mir erst mal wichtig, dass du
verstehst was du da tust. Denn dafür, dass du allgemeine
Programmierkenntnisse besitzt, schwächelst du da ganz schön.
Nur ob ich es richtig verstanden habe.
Mein Mikrocontroller hat 16mhz;
und ich muss auf 1 mHz kommen um pro us einen Interrupt zu haben.
Also lass ich den immer bis 16 hochzählen um 1mHz zu bekommen.Was
1000000 Interrupts pro Sekunde, also 1 pro us entspricht
stimmt doch oder?
MFG Pietus3
Jan Meyer schrieb:> und ich muss auf 1 mHz kommen um pro us einen Interrupt zu haben.
Nee, wenn du 1 mHz hast, dann hast du pro 1000s einen Interrupt.
Wenn du wirklich pro µs einen willst, brauchst du 1 MHz.
?? schrieb:> Nee, wenn du 1 mHz hast, dann hast du pro 1000s einen Interrupt.> Wenn du wirklich pro µs einen willst, brauchst du 1 MHz.
Du schreibst gleichzeitig das 1 mHz richtig und falsch ist.
Jan Meyer schrieb:> ?? schrieb:>> Nee, wenn du 1 mHz hast, dann hast du pro 1000s einen Interrupt.>> Wenn du wirklich pro µs einen willst, brauchst du 1 MHz.>> Du schreibst gleichzeitig das 1 mHz richtig und falsch ist.
m = Einheitenvorsatz für "Milli", z.B mg -> Milligramm (1/1000g)
M = Vorsatz für "Mega", z.B. MJ -> Megajoule (1 Mio Joule)
Ok? :-))
Jan Meyer schrieb:> Nur ob ich es richtig verstanden habe.>> Mein Mikrocontroller hat 16mhz;>> und ich muss auf 1 mHz kommen um pro us einen Interrupt zu haben.>> Also lass ich den immer bis 16 hochzählen um 1mHz zu bekommen.Was> 1000000 Interrupts pro Sekunde, also 1 pro us entspricht>> stimmt doch oder?>> MFG Pietus3
Aber ich will dir auch mal auf deine eigentliche Frage eine Antwort
geben.
Wenn du aller 16 Takte einen Interrupt auslöst, dann mußt du natürlich
mit der Abarbeitung dieses Interrupts komplett fertig sein, wenn der
nächste kommt. Und das wird dir mit 16 Takten schwer fallen.
Das hat Karl Heinz schon geschrieben, lies dir seinen Beitrag nochmal
durch, ok?
Jan Peter Meyer schrieb:> Das hab ich auch vor zu ändern dabei ging es nur um die Rechnung.
Die Rechnung selbst stimmt schon, aber in der Praxis ist das so nicht
durchführbar, sonst ist der µC nur noch mit Interrupts beschäftigt, und
nicht mal die schafft er abzuarbeiten. Du solltest also das Raster
größer machen. Beim Faktor 10 hast du schon 160 Takte für einen
Interrupt. Überlege, wie "fein" du die Auflösung brauchst und lege dann
die Interrupt-Rate fest.
Karl Heinz schrieb:> Die 20ms sind beim Servoansteuern das unwichtigste überhaupt.
Wenn, dann sowieso 22.5ms. Das ist der uebliche Wert, auch wenn allerlei
Webseiten Anderes behaupten. Die haben aber nicht nachgemessen.
> Leider gibt es da 2 Definitionen. Die meisten Firmen definieren den Puls> als 1ms - 2ms (mit einer Mitte von 1.5ms).
Auch das wird zwar gerne auf Webseiten angegeben, trifft aber in der
Praxis praktisch nicht zu. Der kleinste Range, den ich bisher gemessen
habe, ist 0.9ms bis 2.1ms. Teilweise mehr, aber nie weniger - hoechstens
bei Servotestern.
> Eine einzige Firma, deren Name mit 'Multi' beginnt und mit 'plex' endet,> hat auch noch aus historischen Zeiten andere Pulsdauern im Gebrauch.
Multiplex hatte frueher eine andere Mittelstellung, 1.6ms statt 1.5ms.
Die Dauer lag auch da schon bei den ueblichen 1.2ms.
Achtung bei der Ansteuerung von HF-Modulen - Futaba moechte da zum
Beispiel 1.4ms als Mitte sehen.
Mit dem Timer 1 läuft der Servo jetzt perfekt. Hab auch die Interrupt
Zeit angepasst, Damit er besser läuft. Nun wollte Ich das gleiche
Programm über den 8-Bit Timer 0 laufen lassen. Also hab ich alle
Register so geändert das es für den Timer 0 gilt. Nun läuft es nicht
mehr. Gibt es dafür einen Grund oder hab ich doch aus versehen ein
falsches-Register gesetzt.
Jan Meyer schrieb:> Mit dem Timer 1 läuft der Servo jetzt perfekt. Hab auch die Interrupt> Zeit angepasst, Damit er besser läuft. Nun wollte Ich das gleiche> Programm über den 8-Bit Timer 0 laufen lassen. Also hab ich alle> Register so geändert das es für den Timer 0 gilt. Nun läuft es nicht> mehr. Gibt es dafür einen Grund oder hab ich doch aus versehen ein> falsches-Register gesetzt.
Ich tippe mal, die richtigen Register falsch gesetzt. Jedes gesetzte Bit
in den Timer0 Registern anhand des Datenblattes auf ihre Funktion mit
denen des Timer1 verglichen? Timer0 kann nur bis 255 laufen. Zahlenwerte
im Programm daraufhin überprüft? Grundsätzlich würd ich sagen, daß es
für das nicht mehr laufen einen Grund gibt.