Hallo Leute, anbei habe ich mein Problemkind gepackt. Die Schaltung, wie sie im PDF zu sehen ist, habe ich mit Ausnahme des Adapters K5 auf einem Testboard nachgebaut. Zur optischen Anzeige habe ich noch an den Servoausgängen je eine LED hängen. Es ist soll eine Servosteuerung werden, welche recht einfach gehalten ist. Sie dient für meine Experimentierstrecke zur Weichensteuerung durch Servos. Je eine LED über den Tasten soll den Umlauf optisch anzeigen (Blinklicht). Die Bedienung soll durch einfachen Tastendruck auf S2 für Linkslage, bzw. S3 für Rechtslage erfolgen. Ausgangslage der Steuerung ist eine enfache Servoansteuerung, welche ich mir aus den Videos von Stefan Wintgen auf YouTube entnommen habe. Wenn ich nun das System starte, werde in der Initialisierung die drei LED's (PB0 .. PB2) für ca. 1 sec. aktiviert und dann wieder deaktiviert. Dies dient der Kontrolle. Danach, nach ca. 1. sec. fangen die LED's PB1 und PB2 an zu leuchten. Gleichzeitig habe die Kontroll-LED'S der Servo ein schnelles Flackern. Eine Taste wurde nicht gedrückt. Auf den externen Taster (PD3 / INT 1 - siehe unten) wird nicht reagiert. Ein angeschlossener Servo macht was er will, wer er was macht. Der Funktionsablauf sollte allerdings so sein: Nach dem Systemstart sollen die beiden Servos (Servo 1 und Servo 2) in Linkslage gehen (falls noch nicht geschehen). Wenn ich jetzt die Taste S3 drücke, sollen die Servos (beide) in Rechtslage wechseln. Während einer Zeit von ca. 5 sec. soll die LED 2 (PB1) blinken. Wenn die Weiche dann in Rechtslage ist, soll beim drücken der Taste S2 soll dann die Servos (wieder beide) in Linkslage wechseln. Gleichzeitigt soll wieder für ca. 5 sec. die LED 1 (PB0) blinken. Der Taster S1, welcher an PD2 (INT0) liegt, wird erstmal nicht verwendet. Der externe Taster 1, welcher an PD3 (INT1) liegt, soll das System in den Programiermodus setzten. Der Programiermodus dient später dazu, die Werte für die Servoendlage fein einzustellen und ins EEPROM zu schreiben. Noch ist diese Funktion nicht implementiert, lediglich die ISR ( INT1_vect ) ist hierfür vorhanden. Sobald der MC in dem Programiermodus ist, soll die LED 3 (PB2) blinken und kein Umstellen der Servos mehr erlauben. Der Timer0 (8-Bit) dient dazu, die Taktperiode von 25ms zu generieren. Da es nur ein 8-Bit ist, musste ich mir etwas einfallen lassen, um auf 25000 Impule zu kommen. Der Timer1 (16-Bit) dient dazu, die Impulsweite zu generieren. Dazu verwende ich den Timer1_CompA für den Servo 1 und den Timer-CompB für den Servo 2. Was ich jetzt noch nicht implementiert habe, ist das Entprellen der Taster und auch das Speichern der Servoendlagenwerte im EEPROM. Daher arbeite ich mit festen Werten für die Servoendlage. Zum testen sollte dies reichen. Ich weis, das es nicht der Weisheit letzter Schluss ist und auch der Code sicher noch optimiert werden kann. Und ja, es ist noch Test-Code drin, welcher später dann entfernt werden wird. Weis jemand, wo ich den Fehler gemacht habe, bzw. was die Ursache ist, weshalb es nicht funktioniert? Woher kommt das Dauerleuchten von LED 1 und LED 2 (PB0 und PB1)? Das Flacker der Servo-LED's könnte ich mir erklären, wenn der angeschlossene Servo beim Start in die Linkslage gehen würde und dort bleibe. Aber da er teilweis hin und her geht, kann da auch etwas nicht stimmen. Liebe grüße, Sarah
Viel zu kompliziert. Sieh dir in Modellbauservo Ansteuerung den letzten Codeabschnitt an. Dort findest du Code, der maximal 8 Servos mit einem einzigen Timer ansteuern kann. Alles was du noch einbauen musst sind deine Taster. Da du sowieso für jede Endlage eine eigene Taste benutzt, brauchst du nichts entprellen und du brauchst auch keine Interrupts um die Tasten abzufragen. Alles was du tun musst, ist bei gedrückter Taste dem jeweiligen Servo im globalen Array den richtigen Verdrehwert zuzuweisen. Im Beispiel wird der Timer 2 verwendet, weil sich bei 11Mhz noch einigermassen vernünftige Servo-Positionsabstufungen ergeben. (*) Wenn dir die nicht reichen, dann kann man auch den 16 Bit Timer mit einem anderen Vorteiler benutzen um die Auflösung zu erhöhen. Da aber der 16 Bit Timer ein 'weretvolleres' Gut ist, als der 8-Bit Timer 2, wollte ich den absichtlich nicht für so etwas Profanes wie die Generierung von Servopulsen verwenden. Tip: wenn du weniger als 8 Servos ansteuern willst, dann lass den Code trotzdem so wie er ist und verwende ganz einfach die entsprechenden Ausgänge nicht (bzw. steuere die in der ISR erst gar nicht an). Dann brauchst du dich nämlich nicht um die Wiederholfrequenz der Servopulse kümmern. Die ergibt sich automatisch im richtigen Zeitrahmen, einfach durch das hintereinander Abarbeiten von 8 Pulsen, die sich im Zeitraum von 1 bis 2 ms bewegen und da Servos diesem Detail der Wiederholfrequenz keine allzugroße Bedeutung beimessen, ist es ihnen egal, ob sich der Puls im Zeitraster von 8 ms aufwärts bis ca 16ms wiederholt. Stelle die nicht benötigten Servos auf 1.5ms ein (also Mittelstellung), übergeh sie in der ISR, wenn der entsprechende zugehörige Pin geschaltet werden soll und gut ists. 6*1.5 macht 9ms, dann noch im Mittel 3ms für die beiden übrig gebliebenen Servos mit dazu, macht in Summe 12ms Pulswiederholzeit, was im Normalfall keinerlei Probleme macht. Und wenn doch, dann stellst du eben die nicht benötigten Servos auf 2ms um die Kompletzeit für einen Durchlauf durch alle Servos in die Höhe zu treiben. Diese Zeit für die Pulswiederholung ist bei der Generierung von Servopulsen das Unwichtigste. (*) gerade nachgerechnet. Bei 8 Mhz kriegst du immerhin noch 64 unterscheidbare Servo-Positionen. Wenn dir das reicht, dann brauchst du am angegebenen Code nicht viel grundsätzliches ändern, sondern nur die Anpassung an den Tiny in den Timer-Konfigurationsregistern machen. Die Änderungen sollten aber überschaubar sein, schliesslich basiert alles auf einem ganz gewöhnlichem Timer-Modus mit aktiviertem Compare-Match Interrupt.
:
Bearbeitet durch User
> Servo beim Start in die Linkslage gehen würde und dort bleibe. > Aber da er teilweis hin und her geht, kann da auch etwas nicht stimmen. Wenn ich mal annehme, dass es sich nicht um einen Programmfehler handelt: Servos können Dreckschweine sein, wenn es darum geht die Versorgungsspannung zu verunstalten. Bei mehreren Servos und einem µC an derselben Stromversorgung sollte man der Qualität und der Siebung der Versorgungsspannung besonderes Augenmerk schenken.
Hallo Karl Heinz, erst einmal vielen dank für deine Antworten. Und auch ein kleines sorry, das ich mich erst jetzt melde. Auch wenn ich gerade Urlaub habe, so gibt es doch zu viele Dinge, die ich zu erledigen haben. Aber nun zu deinen Antworten. Ja, es ist schon ein wenig Aufwändig, was ich hier entwickelt habe (auch wenn der Wurm drin ist). Für mich selbst ist es mein erstes wirkliches Porjekt. Und ich finde diese Konfiguration ganz akzeptabel. Sicherlich werde ich im Laufe der Zeit, bzw. bei den weiteren Projekten noch sehr viel lernen und auch sicherlich vieles optimieren. Aktuell aber würde ich mich gerne an diesem Aufwand halten. Ich habe mir den Code mal angeschaut, den du mir empfohlen hast. Ist natürlich kein Vergleich zu meinem, zumal auch eine andere Ausgangslage zugrunde liegt. Aber ich gebe zu, das ich diesen Code zu adaptieren versuche. Was ich aber ändern werde, ist der verwendete Timer. Da ich zum einen nur einen ATtiny habe, stehen mir nur ein 8-Bit und ein 16-Bit zur Verfügung. Und den 16'er habe ich für nichts anderes vorgesehen, wenn ich dieses Code zugrunde lege. In meiner Version habe ich ihn ja schon verwendet, weswegen ich ja auf den 8'er ausweichen musste. Bei der Frequenz liege ich bei 8 MHz, so das ich hier bei dem 8'er nur 64 Servostufen habe und ich nicht glaube, das diese wirklich ausreichen werden. Wie schon geschrieben, soll diese Schaltung zur Ansteuerung einer Weiche via Servo erfolgen und ich denke, das hier eine weitaus feiner Abstufung notwendig ist. Die Weiche soll ja auch gut anliegen und nicht zu weit abstehen, bzw. zu weit an die Schiene drücken soll. Ich möchte weder die Backenschiene überlasten, noch den Servo. Karl Heinz schrieb: > Wenn ich mal annehme, dass es sich nicht um einen Programmfehler > handelt: Was ich nicht wirklich ausschließen kann. Ich habe mich bei der Entwicklung an dem Code von dem Stefan Windgen orientiert und bei der 8-Bit versucht, die einzelnen Register aus dem Datenblatt zu lesen. Da mein Englisch aber für die Tonne ist, kann es sein, das ich den ein oder anderen Registereintrag falsch gesetzt habe.
1 | TCCR0B |= (1<<WGM02) | (1<<CS01); // CTC-Modus + Prescaler = 8 (CPUFrequenz / 8 = 1MHz) |
2 | TIMSK |= (1<<OCIE0B); // Timer-Interupt's für Vergleichswerte |
Bei dem (1<<WGM02) bin ich nicht sicher, da ich glaube im Datenblatt etwas von WGM2 gelesen zu haben. > Servos können Dreckschweine sein, wenn es darum geht die > Versorgungsspannung zu verunstalten. Bei mehreren Servos und einem µC an > derselben Stromversorgung sollte man der Qualität und der Siebung der > Versorgungsspannung besonderes Augenmerk schenken. Ja, davon habe ich schon gehört. Zumal ich auch recht günstige vom C verwende. Was allerdings keine pauschale Ausage sein muss. Ich habe in Sachen Spannung/Versorgung ja auch vorgesehen, diese ein wenig zu entkoppeln (wenn ich das so nennen kann). Wie in der Schaltung zu sehen, habe ich einige Kondensatoren vorgesehen, die auch noch in der Größe variabel sind. Die Stromversorgung des MC ist durch eine Diode und einem eigenen Spannungsregler abgetrennt. Die eigentliche Stromversorgung ist eine kleine Platine, welche 5 V liefert, auch hier sind einige Kondensatoren vorgesehen, die auch noch an Kapazität vergrößert werden können. Letztlich wird es der wirklich Einsatz am Modul zeigen, ob es was bringt. Sobald ich den Code angepasst habe, werde ich berichten. Liebe grüße, Sarah
Sarah S. schrieb: > Sobald ich den Code angepasst habe, werde ich berichten. Dein Code ist wirklich viel, viel, viel zu kompliziert, wenn Du nur 3 Tasterstellungen auswerten und danach drei Servos ansteuern möchtest. Im Endeffekt brauchen die Servos nur alle 20 Millisekunden (=20000µs) je einen Refresh-Impuls mit einer Dauer zwischen ca. 1500 und 2500 µs. Solange nichts anderes zu steuern ist, brauchst Du kaum mehr als das von Karl Heinz verlinkte Beispiel "Signalerzeugung für 1 Servo" auf drei Servos aufzubohren. Pseudocode für die Hauptschleife: - int servotime[3]; - Wenn Taster1 unten servotime[0]=1500; else servotime[0]=2500; - Wenn Taster2 unten servotime[1]=1500; else servotime[1]=2500; - Wenn Taster3 unten servotime[2]=1500; else servotime[2]=2500; - Ersten Servo HIGH - _delay_us(servotime[0]); - Ersten Servo LOW - Zweiten Servo HIGH - _delay_us(servotime[1]); - Zweiten Servo LOW - Dritten Servo HIGH - _delay_us(servotime[2]); - Dritten Servo LOW - _delay_us(20000-servotime[0]-servotime[1]-servotime[2]); Und damit ist ein 20ms Intervall voll und Du fängst von vorne an.
:
Bearbeitet durch User
Jürgen S. schrieb: Servus Jürgen, > Dein Code ist wirklich viel, viel, viel zu kompliziert, wenn Du nur 3 > Tasterstellungen auswerten und danach drei Servos ansteuern möchtest. Letztlich sind es nur zwei Taster und auch nur 2 Servos. Also noch weniger Code, als du unten vorgeschlagen hast. Eventuell kommt noch eine zweite Option dazu, wo jeder Servo mit je einem Tasten gestellt wird. > > Im Endeffekt brauchen die Servos nur alle 20 Millisekunden (=20000µs) je > einen Refresh-Impuls mit einer Dauer zwischen ca. 1500 und 2500 µs. > > Solange nichts anderes zu steuern ist, brauchst Du kaum mehr als das von > Karl Heinz verlinkte Beispiel "Signalerzeugung für 1 Servo" auf drei > Servos aufzubohren. Nein, bis auf die beiden Servos und je eine LED pro Seite gibt es nicht viel, was zu machen ist im Regelbetrieb. Der geplante Programmiermodus ist davon unabhängig. Eventuell kommt noch die dritte Tase ins Spiel, welche als "Not-Aus" angedacht war. Da müsste ich aber noch wissen, wie ich einen Servo in einem Umlauf, der doch recht kurz ist, sofort anhalten kann. Aber das ist jetzt nicht wichtig, sondern lediglich eine Option. > > Pseudocode für die Hauptschleife: > - int servotime[3]; > - Wenn Taster1 unten servotime[0]=1500; else servotime[0]=2500; > - Wenn Taster2 unten servotime[1]=1500; else servotime[1]=2500; > - Wenn Taster3 unten servotime[2]=1500; else servotime[2]=2500; > - Ersten Servo HIGH > - _delay_us(servotime[0]); > - Ersten Servo LOW > - Zweiten Servo HIGH > - _delay_us(servotime[1]); > - Zweiten Servo LOW > - Dritten Servo HIGH > - _delay_us(servotime[2]); > - Dritten Servo LOW > - _delay_us(20000-servotime[0]-servotime[1]-servotime[2]); > > Und damit ist ein 20ms Intervall voll und Du fängst von vorne an. Einfaches Prinzip, was mir sogar gut gefällt. Karl Heinz hatte ja den Code von den 8 Servos ins Spiel gebracht, was natürlich umfangreicher wäre, als dein Vorschlag. Wenn man mal von dem Beiwerk wie LED's blinken lassen, verzögerungen einbauen, gegenläufige Umstellung verhindern, etc. absieht. Liebe grüße, Sarah
Sarah S. schrieb: > Wenn man mal von dem Beiwerk wie LED's blinken > lassen, verzögerungen einbauen, gegenläufige Umstellung verhindern, etc. > absieht. Der Code dauert pro Umlauf ziemlich genau 20 Millisekunden. Durch einfaches Aufaddieren von 20 pro Durchlauf auf einen beispielsweise unsigned long, erhältst Du einen Millisekundenzähler mit einer Auflösung von 20 Millisekunden. Solange die Aktionen, die Du zwischendurch noch durchführen möchtest, z.B. Blinken an LEDs, recht schnell angesteuert werden im Vergleich zu einem 20ms Intervall, und solange keine höhere zeitliche Auflösung als diese ca. 20ms verlangt wird, läßt sich das dann wunderbar über den Stand des Millisekunden-Zählers abstoppen, z.B. eine LED nach Bedarf jeweils 0,58s ein zu schalten dann wieder für 0,42s aus zu schalten. Oder wie auch immer. Da in meinem Pseudocode Eingabe- und Ausgabe bereits getrennt sind, kannst Du durch Logikbedingungen, die Du nach dem Abfragen der Taster aber vor dem Ansteuern der Servos einfügst, auch ganz leicht unsinnige Tasterstellungen ausfiltern. Mit dem oben skizzierten Pseudocode bekommst Du sowohl die Servorefresh-Impulse alle (circa) 20 Millisekunden sehr exakt zeitlich gesteuert, UND darüber bekommst Du einen 20-Millisekundentakt, den Du einfach nur aufaddieren brauchst, um weitere, langsame Aktionen zu steuern.
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.