Hallo, hab heute meinen ersten Servomotor an meinen Atmega8 angeschlossen gg. Das mit dem 20ms und 2ms hab ich also verstanden und hin gebracht. Nun die Frage: Wie sage ich meinem Servo in welche Richtung er sich bewegen soll. MfG Dominik
Dominik Fa schrieb: > Das mit dem 20ms und 2ms hab ich also verstanden >... > Wie sage ich meinem Servo in welche Richtung er sich bewegen soll. Die Position des Servos ergibt sich aus der Länge des kurzen Impulses. Der darf zwischen 1ms und 2ms lang sein. Oliver
Hallo Dominik, die Suchfunktion mit "Servo" liefert fst 1000 Treffer! Da sollte doch was passen ;) hans
So weit ich das verstanden habe schauen die Impulse wie folgt aus: 1ms high, 19ms low: links Position 1.5ms high, 18.5ms low: mittlere Position 2ms high, 18ms low: rechte Position Wenn des jetzt so stimmt, heißt das für ich muss mir ein Oszi zulegen um meine Impulse zu prüfen ob ich da keinen rechen Fehler habe.
Dominik Fa schrieb: > So weit ich das verstanden habe schauen die Impulse wie folgt aus: > > 1ms high, 19ms low: links Position > 1.5ms high, 18.5ms low: mittlere Position > 2ms high, 18ms low: rechte Position > Genau. Wobei nur die 1ms - 2ms kritisch sind. Ob die Pause 10ms oder 15ms oder 20ms beträgt, ist für die meisten Servos uninteressant. Die Länge des Pulses ist das was zählt. > Wenn des jetzt so stimmt, heißt das für ich muss mir ein Oszi zulegen um > meine Impulse zu prüfen ob ich da keinen rechen Fehler habe. Wie wäre es, wenn du einfach mal dein Programm zeigst? Dann könnten wir dir helfen, zb indem jemand überprüft, ob dein Timing stimmt.
Ich habe angenommen das der Takt 4MHz ist und ich mit einem Vorteiler von 8, auf 512µs komme. Vielen danke für die Bemühungen und die Unterstützung.
Dominik Fa schrieb: Moment! > Ich habe angenommen das der Takt 4MHz Was soll das heißen? Hast du einen 4Mhz Takt oder hast du ihn nicht! Servo Ansteuerung ist hauptsächlich eine Timing Sache. Wenn man sich schon auf die allem zugrundeliegende Basisfrequenz nicht verlassen kann, macht es keinen Sinn weiterzumachen. Hast du oder hast du nicht? Hast du das überprüft?
Du brauchst kein Oszi. Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das dann alles mit ISR funktioniert. AVR-Tutorial Dein Einsprungspunkt in die ISR ist bei timer0_overflow. Jeder einzelne Pfad, den das Programm nehmen kann, muss letztendlich in einem reti münden! In deinem Programm kommen viel zu viele rjmp wait vor! Idelaerweise hast du nur eine einzige von diesen Endlosschleifen. Und die befindet sich in main: Nachdem der Grundaufsatz erledigt ist, geht main in eine Endlosschleife über. Durch dein hin und her Springen hast du dir selbst den Überblick über dein Programm genommen, sodass du nicht mehr nachvollziehen kannst, was wann wo passiert. Da hilft dir auch dein sei rjmp wait innerhalt der ISR nichts mehr. Ein sei, der in einer ISR auftaucht, ist fast immer ein Fehler. Ein Profi, der weiß was er tut, und was er sich damit einhandelt kann das machen. Aber für einen Newbie ist so etwas tödlich.
Karl heinz Buchegger schrieb: > Du brauchst kein Oszi. > Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit > Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das > dann alles mit ISR funktioniert. > > AVR-Tutorial Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal mit einem Mega8 mit 4 MHz. Eigentlich braucht Dominik nur mal etwas durch die Threadliste schmökern, denn da laufen aktuell mehrere Threads zum Thema Servo. Da ist alles erklärt, was man dazu wissen sollte. Ich habe mir den Quältext kurz angesehen, kann ihm (betreffs Programmierstil) aber nichts abgewinnen. Timer-Overflow-Interrupt war eine nette Sache, als es noch keine Compare-Interrupts gab. Die Zeiten sind vorbei, zumindest bei aktuellen AVRs. Auch sonst enthält dieser Quältext allerhand Unsinn. Also, Dominik, ehe Du ohne Erfahrung weiter draufloswirtschaftest und dann auf Hilfe hoffst, solltest Du erstmal schaun, wie es andere machen. Ich meine dabei nicht unverstandenes Abschreiben, sondern Analysieren fremder Programme. Sollte es an dieser oder jener Stelle zu Fragen kommen, so wird sich sicher jemand finden (auch ich), der Dir mal einen entsprechenden Hinweis gibt.
Kluchscheißer Kluchscheißer schrieb: > Karl heinz Buchegger schrieb: >> Du brauchst kein Oszi. >> Du brauchst eine Einführung in Programmierung. Im speziellen wie das mit >> Unterprogramaufrufen funktioniert. Und da wieder im Speziellen, wie das >> dann alles mit ISR funktioniert. >> >> AVR-Tutorial > > Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne > weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal > mit einem Mega8 mit 4 MHz. Schon klar. Aber auch das Tuorial beginnt damit, einen Quarz bzw. Quarzoszillator mit 4Mhz an den Mega8 anzuschliessen :-) > Auch sonst enthält dieser Quältext allerhand Unsinn. Hab ich zuerst auch gedacht. Aber wenn man das mal durchgeht ist es gar nicht sooo schlimm. Interrupts und was da in der ISR zu passieren hat wurde nicht verstanden. Der Code kommt mir vor wie von einem BASIC Umsteiger: Hauptsache ich kann mit einem GOTO irgendwo hinspringen - das ist cool. Wenn man sich das wegdenkt , ist der Rest nicht mehr so schlimm. Das man das Servo nur auf eine Handvoll Positionen einstellen kann, mangels Teil-Möglichkeiten durch den Timer-Overflow, ist zwar eine heftige Einschränkung, aber sollte dem Spass erst mal keinen Abbruch tun.
muss man da nicht auch beachten, dass _delay_m/us(XXX) nicht ganz genau ist, und auch der interne Quarz nicht ganz genau ist??
Marcus B. schrieb: > muss man da nicht auch beachten, dass _delay_m/us(XXX) nicht ganz genau > ist, und auch der interne Quarz nicht ganz genau ist?? Im Prinzip ja. Allerdings * ist das ein Assembler Programm * benutzt er keine _delay_ms * ist die Ungenauigkeit im Quarz klein genug, dass sie sich in der Servoposition höchstens um ein paar Hundertstel Grad bemerkbar machen wird. Und ob ein Servogetribe mechanisch diese Genauigkeit überhaupt liefert, darf getrost bezweifelt werden. Für praktische Zwecke ist das genau genug.
Karl heinz Buchegger schrob im Beitrag #1711490 u.A.: >> Und schon ist geklärt, woher die Mär stammt, der Mega8 würde ohne >> weiteres Zutun mit 4 MHz laufen. ;-) Denn das Tutorial arbeitet nunmal >> mit einem Mega8 mit 4 MHz. > > Schon klar. > Aber auch das Tuorial beginnt damit, einen Quarz bzw. Quarzoszillator > mit 4Mhz an den Mega8 anzuschliessen :-) Das ist ein alter Zopf aus der Zeit, als das Tutorial mit dem AT90S4433 gearbeitet hat. Beim Mega8 reicht es nicht, einen Quarz anzuschließen, man muss ihn auch per Fusebits anmelden. Dies ist für ein Tutorial ein unnötiges Risiko, denn ein Anfänger (wer sonst braucht ein Tutorial) kann den AVR leicht verfusen und sich für ISP aussperren. Und das, wo der Mega8 die meisten Aufgaben ganz gut im Auslieferungszustand (mit internem Takt von 1MHz) erledigen kann. > Der Code kommt mir vor wie von einem BASIC > Umsteiger: Hauptsache ich kann mit einem GOTO irgendwo hinspringen - das > ist cool. GOTO ist auch in BASIC ein alter Zopf. Dafür gibt es Declare Sub/Function und das einfache Aufrufen mit Namen, sowie Exit Do/For zum stackverträglichen Verlassen von Schleifen. ASM stelle ich mir aber ohne JMP recht schwierig vor. In jeder Sprache kann man schlecht programmieren. In diesem Forum sehe ich z.B. mehr schlechten C-Code als schlechten Basic-Code, weil hier einfach mehr C-Anfänger vertreten sind. ;-) Dein Eindruck, dass BASIC-Leute einen schlechten Programmierstil haben, stimmt aber, denn an vielen Bildungsstätten wird eine Einführung in BASIC von Ausbildern gelehrt, die selbst keine Ahnung davon haben. > > Wenn man sich das wegdenkt , ist der Rest nicht mehr so schlimm. Das man > das Servo nur auf eine Handvoll Positionen einstellen kann, mangels > Teil-Möglichkeiten durch den Timer-Overflow, ist zwar eine heftige > Einschränkung, aber sollte dem Spass erst mal keinen Abbruch tun. Naja, mit einem Timertakt von 1µs und Compare-Werten zwischen 1000 und 2000 lässt sich ein (oder mehrere!) Servo(s) schon recht präzies steuern. Und dazu reicht ein CPU-Takt von 1MHz (Auslieferungszustand) völlig aus. Gruß in die Berge...
Irgendwie befürchte ich dass ich vor lauter Bäume den Wald nicht sehe. Gut, am besten ist wohl wenn ich mir noch mal Interrupt auf der Zunge zergehen lasse.
Dominik Fa schrieb: > Irgendwie befürchte ich dass ich vor lauter Bäume den Wald nicht sehe. > fang einfach bei timer0_overflow zu lesen an. verfolge jede Verzweigung, die in diesem Unterprogramm genommen werden kann. Jeder einzelne Pfad, der durch dieses Unterprogramm existiert, muss letztendlich in einem reti enden! Egal wieviele Verzweigungen es gibt (und daher ist es schlau, wenn man nicht wie ein wilder hin und her springt, denn dann wird es immer schwieriger das nachzuvollziehen)
Hab den Servo jetzt Unterkontrolle. Ich glaub meine Programmstruktur schaut auch etwas besser aus. Ein Oszi hab ich auch angehängt um mir das Ganz etwas anschaulicher zu machen. Zu dem Kommentar: die Suchfunktion mit "Servo" liefert fst 1000 Treffer! Man bekommt vielleicht viele Treffer, aber es würde nicht so viele Beiträge dazu geben wenn ein Servo irgendwo gut erklärt wäre. Vielleicht ein Punkt den man noch ins Tutorial einbaut.
Dominik Fa schrieb: > Hab den Servo jetzt Unterkontrolle. > > Ich glaub meine Programmstruktur schaut auch etwas besser aus. Noch nicht wirklich Schauen wir uns mal ein paar Stellen an
1 | main: |
2 | out PORTD, r16 |
3 | rjmp main |
Warum wird hier an Port D ausgegeben, an dem dein Servo hängt? Entweder du erledigst alle Servosteuerungen in der ISR oder du erledigst sie in main. Aber nicht beides. Das führt über kurz oder lang immer zu unliebsamen Interaktionen zwischen verschiedenen Programmteilen
1 | timer0_overflow: |
2 | cpi r16, 0b01111111 |
3 | BREQ dec_servo_h |
4 | BRNE dec_servo_l |
Sieh dir das einmal genau an. Du benutzt einen BREQ um bei Gleichheit einen anderen Weg zu gehen. Wenn dieser Weg aber nicht genommen wird, weil eben keine Gleichheit vorhanden ist, dann MUSS das nächste BRNE wahr sein und springen. Es besteht kein Grund da noch einmal zu testen, weil dieser Test immer wahr sein wird. Wenn du die nachfolgenden Codestücke umdrehen würdest, dann bräuchtest du nur im BREQ Fall springen, im gegenteiligen Fall gehts dann einfach im Code weiter. Oder aber natürlich im BRNE Fall. Wie auch immer du das haben willst, aber eine Abfrage ist überflüsig.
1 | timer0_overflow: |
2 | cpi r16, 0b01111111 |
3 | BRNE dec_servo_l |
4 | |
5 | dec_servo_h: |
6 | dec servo_h |
7 | breq set_servo_l |
8 | ldi r16, 0b01111111 |
9 | out PORTD, r16 |
10 | reti |
11 | |
12 | dec_servo_l: |
13 | dec servo_l |
14 | breq set_servo_h |
15 | ldi r16, 0b01111110 |
16 | out PORTD, r16 |
17 | reti |
Aber im Grunde machst du das ungeschickt. Denn im Grunde würdest du nur 1 Zähler benötigen, der einfach nur die 'Zeit' runterzählt, bis wieder eine Aktion am Portpin notwendig ist. Ein Portpin behält sowieso seinen Wert solange, bis du ihn änderst. Das hätte dann den Vorteil, dass du so schnell wie möglich wieder aus der ISR rauskommst, nämlich dann, wenn die Zeit noch nicht gekommen ist, irgendetwas an den Portpins zu machen. Ausserdem brauchst du dann 1 Register weniger.
1 | timer0_overflow: |
2 | dec wait_time |
3 | BREQ flip_pin |
4 | reti |
5 | |
6 | flip_pin: |
7 | cpi r16, 0b01111111 // wie steht der Pin jetzt |
8 | BREQ dec_servo_l // auf 1, muss auf 0 |
9 | |
10 | dec_servo_h: // Pin ist low, auf high setzen |
11 | ldi r16, 0b01111111 |
12 | out PORTD, r16 |
13 | ldi wait_time, 0x05 |
14 | reti |
15 | |
16 | dec_servo_l: // Pin ist high, auf low setzen |
17 | ldi r16, 0b01111110 |
18 | out PORTD, r16 |
19 | ldi wait_time, 0x48 |
20 | reti |
Der Code ist kürzer, einfacher und es gibt weniger Pfade durch die ISR, auf die man achten muss. Das ist jetzt noch kein grosses Thema, aber spätestens dann, wenn Register gesichert und wiederhergestellt werden müssen (denk zb an das SREG Register) wird das zu einem wichtigen Punkt.
Hab meine Schaltung auf zwei Servos aufgestockt. Welche jeweils 3 Positionen einnehmen. Pro Servo habe ich dazu zwei Schalter mit denen ich die Postion festlege. Um mich auch ein bisschen in logische Operationen zu üben, werden beide über einen Port ausgegeben. Da ihr ja schon wisst das ich noch nicht viel Erfahrung habe wollte ich fragen ob mein Lösung OK ist, oder was besser gemacht werden könnte.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.