Hallo allerseits, folgendes hab ich vor: ich habe einen ATmega168 auf einer fertigen Platine. 4 Ausgänge gehen auf jeweils ein Schieberegister (74HC595). Insgesamt hängen an den Schieberegistern 18 Servos die mit PWM(50Hz) angesteuert werden. Ich habe vor mit den 4 Augängen alle 18 Motoren zu steuern. So wie ich das verstanden habe, lege ich seriell ein 8-bit-Wort an das schieberegister an. Mit entsprechendem Trigger wird dann das (vorherige) Wort parallel an den 8 Ausgängen des Schieberegisters ausgegeben. Da ja die Pulsdauer zwischen 1ms und 2ms ist möchte ich Pulse mit einer genauigkeit von 10 us ausgeben. Ich habe mir diverse Tutorials zu den Timern durchgelesen aber in diesen wird nur beschrieben wie man an einem Ausgang beim interrupt einen Aktion auslösen kann. Ich hatte jedoch vor alle 10 us ein 8-bit Wort seriell an jeden der 4 Ausgänge zu schicken. Hat jemand mit sowas Erfahrung und/oder ein besseres Tutorial? Danke im Vorraus. MfG idler
idler schrieb: > Ich habe mir diverse Tutorials zu den Timern durchgelesen aber in diesen > wird nur beschrieben wie man an einem Ausgang beim interrupt einen > Aktion auslösen kann. Die Aktion im Interrupt unterscheidet sich in nichts von einer Aktion ausserhalb eines Interrupts. Ob du einen Portpin in einer ISR von 0 auf 1 schaltest oder ausserhalb, ist dem Port völlig egal. > Ich hatte jedoch vor alle 10 us ein 8-bit Wort seriell an jeden der 4 > Ausgänge zu schicken. Ja dann mach das doch. Aber du musst die Strategie ein wenig ändern. Du bereitest die Werte in der Schiebekette vor und nach µS wird die Schiebekette auf die Ausgänge durchgeschaltet. Danach hast du wieder 10µS Zeit, die Schiebekette auf den nächsten Zustand vorzubereiten, der dann zum richtigen Zeitpunkt durchgeschaltet wird. Wenn du zum 10µS Zeitpunkt erst anfängst die Bits auszugeben, bist du zu spät drann. PS. Du schickst kein 8-Bit Wort an 'jeden der 4 Ausgänge'. Die 4 Ausgänge müssen zusammenspielen um 1 Byte zu übernehmen. http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister Und leg dir für deine ersten Versuche nicht das 10µS Raster zugrunde. Dein erster Schritt sollte sein: Ich hab da ein Byte und will, dass die Schieberegister Ausgänge genau den Bits dieses Bytes entsprechen. Wie muss ich die 4 Schieberegistersignale bedienen, damit die Bits dort hinwandern.
Hi. Du kannst das ganze auch anders machen: Du hängst an jedes bit des Schieberegisters ein Servo. Dann schiebst du ein einzelnes 1-bit durch das ganze register, d.h. es ist immer nur ein ausgangsbit des rigisters auf 1. Du schiebst also dieses bit ins erste Ausgangsbit. nach 1 - 2 ms schiebst du es ein bit weiter (clk toggeln). dadurch wird ausgangsbit 1 0 und ausgangsbit 2 1 und der Servo an Ausgangsbit 1 hat seinen impuls gehabt. Ich denke, das ist einfacher als immer das ganze register zu beschreiben. Und in den alten analogen Fernsteuerungen wirds auch so gemacht. Bernhard
Bernhard Mayer schrieb: > Du hängst an jedes bit des Schieberegisters ein Servo. > Dann schiebst du ein einzelnes 1-bit durch das ganze register, d.h. es > ist immer nur ein ausgangsbit des rigisters auf 1. > Du schiebst also dieses bit ins erste Ausgangsbit. nach 1 - 2 ms > schiebst du es ein bit weiter (clk toggeln). dadurch wird ausgangsbit 1 > 0 und ausgangsbit 2 1 und der Servo an Ausgangsbit 1 hat seinen impuls > gehabt. Hmm. Das ist eigentlich ziemlich clever! Danke für die Anregung
>Das ist eigentlich ziemlich clever!
So arbeiten Modellfernsteuerungen schon diverse zig Jahre...
bitte gern geschehen. Man kann dann auch einfache Schieberegister ohne integriertem Latch nehmen, also z.B. 74HC164. und man braucht dann auch nur 2 pins am Mikrocontroller, wenn man den MR unbeschaltet lässt. Allerdings muss man dann auf die gesamte Zykluslänge achten. Denn wenn die ganzen Servopulse auf 2 ms stellt, ist bei 8 Servos die minimale Zykles/Refreshzeit 16 ms, bei 18 Servos 38 ms. Bernhard
STK500-Besitzer schrieb: >>Das ist eigentlich ziemlich clever! > > So arbeiten Modellfernsteuerungen schon diverse zig Jahre... Schon klar, nur ist mir noch nie in den Sinn gekommen, so etwas mit einem µC, einem Schieberegister und der zeitlichen Steuerung des Clock-Signals zu machen. Ich hab da immer viel komplizierter gedacht :-)
Bernhard, großartige Idee, großes Kompliment! Ressourcenschonend mit einem Interrupt zu implementieren. Gruß Jörg
Ich soll eine nämlich eine Software schreiben für eine fertige Schaltung. Alle 4 Schieberegister teilen sich eine SER/Mosi- und eine SCK- Leitung. Lediglich die RCK-Pins werden separat angesteuert. Wenn ichs gerafft habe muss ich über Mosi, immer wieder 1000 0000 schicken und mit einer Rate von 8bit/20ms (wegen den 50 Hz für den Servo) mit SCK durchschalten. Aber wie kann ich über die RCK-Leitung angeben, wie lange der Puls dauert? Ich dachte der RCK reagiert nur auf ne Flanke und kopiert dann das aktuelle Schieberegister auf die Ausgänge. Wenn ich was falsch versteh, bitte bescheid geben. Bin Neuling in uc-Programmierung. Danke nochmal
Hi. hast du ein Schaltbild? Sind die 4 schieberegister hintereinander oder parallel geschaltet? Bernhard
Sind zwar noch ein paar Reste von anderem Zeug drin, aber hier, siehe Anhang. Aber das mit dem RCK Signal hab ich glaub ich grade selber gerafft. Einfach erst nach (20 ms - Pulsdauer) RCK auf High.
idler schrieb: > Alle 4 Schieberegister teilen sich eine SER/Mosi- und eine SCK- Leitung. > Lediglich die RCK-Pins werden separat angesteuert. Wär eigentlich gar nicht notwendig > Wenn ichs gerafft > habe muss ich über Mosi, immer wieder 1000 0000 schicken und mit einer > Rate von 8bit/20ms (wegen den 50 Hz für den Servo) mit SCK > durchschalten. Die 20 ms sind nicht tragisch. Um die musst du dir erst mal keine grossen Sorgen machen. SCK alleine reicht nicht. Hast du dir das Prinzip eines Schieberegisters im Tutorial angesehen? Mit SCK schiebst du deine Daten durch die Register durch. Das heißt aber noch lange nicht, dass deswegen auch die Outputpins die Werte verändern. Erst mit einem Puls an RCK wird der Inhalt der Schiebekette auf die Ausgangspins durchgeschaltet. Deine Schieberegister sehen so aus +--------+ +--------+ |00000000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 00000000 00000000 Jetzt schiebst du mit der Datenleitung und SCK eine 1 an die erste Stelle vom Schieberegister +--------+ +--------+ |10000000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 00000000 00000000 Die erscheint noch nicht am Ausgang. Erst dann wenn du über RCK einen Puls schickst kommt diese 1 an den Ausgang RCK Puls kommt +--------+ +--------+ |10000000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 10000000 00000000 Ab jetzt beginnt die Zeit zu laufen. Gleichzeitig schiebst du mit einem SCK die 1 um 1 Stelle weiter +--------+ +--------+ |01000000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 10000000 00000000 Sagen wir mal 1.5 ms nach dem ersten RCK machst du den nächsten RCK. Dann übernehmen die Ausgänge des Schieberegister den Inhalt der SChiebekette +--------+ +--------+ |01000000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 01000000 00000000 Zwischendruch wieder ein SCK um die 1 in der Kette weiterzuschieben +--------+ +--------+ |00100000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 01000000 00000000 und nach weiteren 1.2 ms kommt wieder ein RCK +--------+ +--------+ |00100000| --- |00000000| --- | | | | +--------+ +--------+ |||||||| |||||||| 00100000 00000000 Betrachten wir jetzt nur die ersten beiden Ausgänge des Schiebregisters. Wie lange waren sie 1? Nun, der erste war 1.5 ms auf 1, der zweite war 1.2 ms auf 1. Die zeitlichen Abstände des RCK Pulses haben das so ergeben. Das sind aber ganau die Zeiten, die du haben willst. Du willst ja einen Ausgang haben, der 1.5ms auf 1 ist. Und du willst einen anderen Ausgang haben, der 1.2ms auf 1 ist (weil dir die vorgegebenen Servopositionen diese Zeiten diktiert haben). Wenn du einen Ausgang 2.1ms auf 1 haben willst, dann brauchst du nur 2.1ms warten bis der RCK Puls kommt und die 1 an diesem Ausgang wieder durch eine 0 aus der Schiebekette ersetzt. > Aber wie kann ich über die RCK-Leitung angeben, wie lange > der Puls dauert? Gar nicht. Du machst dir einen Timer, der zb. alle 10µs feuert (in Form eines Interrupts). Zusätzlich rechnest du dir aus, wieviele derartige Timer-Feuerungen notwendig sind, damit die Vorganbezeit erreicht wird. Wenn die Vorgabezeit 1.6ms ist und dein ISR alle 0.1ms kommt, dann musst du nur 16 ISR Aufrufe abwarten, bis 1.6ms vergangen sind. Zähler auf 0 setzen und bei jedem ISR Aufruf den Zähler um 1 erhöhen. Hat der Zähler 16 erreicht dann den RCK Pin auf 1 setzen, RCK Pin auf 0 setzen und schon schaltet das Schieberegister durch. Dann noch die 1 in der Schiebekette mit einem SCK Puls um 1 Stelle weiterschalten und ausrechnen welches der nächste Vergleichswert für den Zähler ist. (Und natürlich am vorderen Ende der Schiebekette wieder eine 1 einspeisen, wenn sie am hinteren Ende nach 24 SCK Pulsen rausfällt) Im Grunde baust du nichts anderes als ein 'Lauflicht' bei dem nicht alle Lampen gleich lange brennen, sondern die Brenndauer der 'Lampen' variabel ist und 'zufällig' so getimed sind, dass die Lampenleitungen als Servopulse fungieren können. Und um die 20ms machst du dir erst mal überhaupt keine Gedanken. Die sind bei einer Servoansteuerung normalerweise (ausser vielleicht bei Digitalservos) das Unwichtigste überhaupt. Dich interessiert nur, dass die einzelnen Ausgänge der Schieberegister einen Puls mit der korrekten Länge abgeben. > Ich dachte der RCK reagiert nur auf ne Flanke macht ja nichts. Den RCK Puls musst sowieso du selber erzeugen. Portpin auf 1, Portpin auf 0
nur leider funktioniert das mit der schaltung von idler nicht, da alle 4 schieberegister am gleichen Daten- und Taktpin hängen, d.h. an allen 4 registern würde das gleiche timing rauskommen. Außer du machst es nacheinander schaltest nur den Ausgang von einem register. Dann kannst/darfst du aber die SPI-Funktion vom Mikrocontroller nicht hernehmen. Bernhard
idler schrieb: > Sind zwar noch ein paar Reste von anderem Zeug drin, aber hier, siehe > Anhang. Wieso sind denn die Schieberegister nicht untereinander verbunden? So musst du jetzt Softwaremässig alles mal 4 machen. Wäre doch viel simpler, wenn die SR so verschaltet wären, dass sie wie ein einziges 32 Bit Schieberegister funktionieren würden.
Bernhard Mayer schrieb: > nur leider funktioniert das mit der schaltung von idler nicht, da alle 4 > schieberegister am gleichen Daten- und Taktpin hängen, d.h. an allen 4 > registern würde das gleiche timing rauskommen. Habs gerade gesehen. War schon am Schreiben als die Schaltung eingetrudelt ist. Wer macht denn aber auch sowas! Ist doch viel einfacher, wenn die SR alle nacheinander hängen. Damit ist deine ganze schöne 'Lauflicht'-Idee gestorben. Wär ja auch zu einfach gewesen :-)
Bernhard Mayer schrieb: > Dann kannst/darfst du aber die SPI-Funktion vom Mikrocontroller nicht > hernehmen. Die kann er so und so nicht benutzen.
:
Wiederhergestellt durch User
idler schrieb: > K, dann hab ichs gerafft. > Cool, danke Leute. Vergiss es. Dein Hardware-Designer hat dir einen Strich durch die Rechnung gemacht.
naja, wenn idler die Pins als normale Porterweiterung ansehen würde und mit der "traditionellen" Weise ansteuern würde, könnte man die SPI-Hardware schon verwenden. Nur wär das alles sehr aufwendig und mit dem bit scheiben gehts einfacher.
Karl heinz Buchegger schrieb: > idler schrieb: >> K, dann hab ichs gerafft. >> Cool, danke Leute. > > Vergiss es. > Dein Hardware-Designer hat einen Strich durch die Rechnung gemacht. es geht auch mit der existierenden hardware. nur musst du jeweils nach 8 bits/servos mit den rck pins ein anderes Schieberegister auswählen.
>Schon klar, nur ist mir noch nie in den Sinn gekommen, so etwas mit >einem µC, einem Schieberegister und der zeitlichen Steuerung des >Clock-Signals zu machen. Das Problem an 18 Servos ist höchstens, dass die 20ms-Pulswiederholrunde nicht mehr hinkommt. Eine ähnliche Schaltung gibt es unter http://www.voidpointer.de
ups, hab eure posts vor meinem letzten nicht gelesen. Die Schaltung hab nicht ich gemacht ^^ Aber ich versteh nicht, wieso das nicht funzt. Wenn ich SCK alle 20/8 ms trigger und am MOSI an alle immer die 1000 000 durchschicke, dann hab ich an allen Schieberegistern alle 20/8 ms die "1" eins weiter. Steuern kann ich die Ausgänge also nur über RCK Leitungen. Und da kann ich doch dann nach (20 - $Pulslänge)ms triggern. Dann hab ich doch bei $Pulslänge = 1,5 ms erst 18,5 ms 0 und dann 1,5 ms ne 1.
Ah, ok Denkfehler bei mir. Die 1 geht dann ja nicht nach 1,5 ms wieder weg, oder? Bernhard Mayer schrieb: es geht auch mit der existierenden hardware. nur musst du jeweils nach 8 bits/servos mit den rck pins ein anderes Schieberegister auswählen. Sorry, das hab ich nicht verstanden. Btw. die schaltung geht. Es war schonmal ne Software auf dem uC mit der es ging, aber davon hab ich keinen Code. Ich soll ne neue mit mehreren Funktionen schreiben.
Ah, ok, verstanden. Bei 18 mal Pos 2000 klappt das halt nicht mehr. Irgendne Lösung muss es doch geben :(
>Aber wie kann ich über die RCK-Leitung angeben, wie lange >der Puls dauert? Was ist die RCK-Leitung? Ich finde sie weder im NXP-Datenblatt*) zum 74HC595, noch im Atmega168-Datenblatt. Sind damit dei Slave-Select-Pins des ATMega gemeint? Bzw. die /MR-Pins der Schieberegister? Man muss eigentlich nur ein Mal zu Beginn des 8-Bit-Zyklus eine 1 an den DS-Pin legen und danach Null. Dann lässt man 8 Takte unterschiedlicher Länge durch den µC erzeugen, wie Bernhard es beschrieben hat. Die Hardware-SPI würde ich dafür nicht benutzen, sondern die Daten- und Taktpins per "Hand" bedienen. Im Prinzip müsste der Ablauf so aussehen: Timer initialisieren (allgemeine Einstellungen: Modus und Taktfrequenz setzen) Schleife: Schieberegister auswählen, dessen Servos ihren Impuls erhalten sollen (Index). Compare-Wert des ersten Servos ins Vergleichsregister eintragen Timer starten Warten, bis 8-Bit-Sequenz abgearbeitet wurde Schieberegister Index erhöhen, bzw. wieder von vorne anfangen zu zählen Ende der (Endlos-)Schleife. In der Timer OnCompare-ISR einen SCK-Impuls generieren, damit das Schieberegister Dann wird wird auch der neue OC-Vergleichswert gesetzt. Wenn alle 8 Kanäle bedient wurden, Flagge setzen, die dem Hauptprogramm das Ende des Durchlaufs signalisiert. Die Stellwerte müssen ja irgendwoher kommen. Den Empfang dieser, kann man wunderbar in die Warteschleife packen, wenn das Hauptprogramm auf das Ende eines Schiebregister-Durchlaufs wartet. Da sich die Schieberegister ja die Daten- und Takt-Leitung teilen, kann man leider nicht mit mehreren Timer arbeiten. *)http://www.nxp.com/acrobat_download/datasheets/74HC_HCT595_4.pdf
>Was ist die RCK-Leitung? >Ich finde sie weder im NXP-Datenblatt*) zum 74HC595, noch im >Atmega168-Datenblatt. >Sind damit dei Slave-Select-Pins des ATMega gemeint? >Bzw. die /MR-Pins der Schieberegister? Die Leitung um den Inhalt des Schieberegisters auf die Ausgänge zu schalten. >Man muss eigentlich nur ein Mal zu Beginn des 8-Bit-Zyklus eine 1 an den >DS-Pin legen und danach Null. >Dann lässt man 8 Takte unterschiedlicher Länge durch den µC erzeugen, >wie Bernhard es beschrieben hat. Wenn ich alle 4 Schieberegister zeitlich parallel betreiben will kann ich die Pulslängen nur über die RCK Leitung steuern, da das die einzigen Leitungen sind, über welche sich jedes Schieberegister separat ansteuern lässt. Da weiß ich aber nicht wie, geschweige denn ob das geht. Die andere Möglichkeit ist, über die SCK Leitung die Pulslänge zu steuern, wobei ich nicht mehr alle 4 Schieberegister zeitlich parallel betreiben kann, da sich alle 4 Schieberegister eine SCK Leitung teilen. Da die Frequenz der Servos 50 Hz ist, und eine Pulslänge bis zu 2 ms betragen kann, ist es aber nicht möglich alle 18 Servos (bzw. alle 32 Ausgänge) innerhalb 20 ms zu bedienen. >Die Hardware-SPI würde ich dafür nicht benutzen, sondern die Daten- und >Taktpins per "Hand" bedienen. Soweit bin ich noch nicht, und hab mich da auch noch nicht eingearbeitet. Meinst du ich soll die SCK und Datenleitung nicht über MOSI und SS ansteuern?
Die Schaltung ist zwar nicht optimal, aber auch kein Beiunbruch. Du hast minimal 1ms Zeit, alle Register mit dem gewünschten nächten Bitmuster zu laden. Das ist bequem zu wuppen. Und das Compareregister wird dann mit der Pulsdauer für den aktiven Kanal geladen. Eine 10µs Interruptrate ist völlig unnötig. Die 20ms Pausendauer sind ein Minimalwert, länger stört nicht. Peter
idler schrieb: > Da die Frequenz der Servos 50 Hz ist, und eine Pulslänge bis zu 2 ms > betragen kann, ist es aber nicht möglich alle 18 Servos (bzw. alle 32 > Ausgänge) innerhalb 20 ms zu bedienen. Nochmal: Vergiss die 20ms. Die haben historische Ursachen, bzw Ursachen die nicht in den Servos selbst begründet liegen. Die Servos interessieren sich normalerweise einen feuchten Dreck dafür, ob du die 20ms einhältst oder kürzer oder länger bist. Allzu lang soll die Wiederholzeit natürlich nicht sein, aber ob das jetzt 15 oder 20 oder 25 oder 30ms sind, ist den Servos ziemlich egal. Für die ist nur der ms Puls wichtig, dessen Länge ihnen verrät, welche Position sie anzufahren haben. Wielang die Pause dazwischen ist, bis der nächste Puls kommt, ist nicht relevant (= da steckt keine Information drinnen)(*) > Soweit bin ich noch nicht, und hab mich da auch noch nicht > eingearbeitet. Ähm. Du kannst doch einen Pin auf 1 setzen. Und du kannst einen Pin auch wieder auf 0 setzen. Mehr brauchst du nicht. (*) Disclaimer: Es gibt mitlerweile auch seit einiger Zeit Digitalservos die eine Fail-Safe Sicherung eingebaut haben. Bleiben die Positionspulse zu lange aus, dann fahren sie eine bestimmte Fail-Safe Position an. Von daher gibt es bei diesen Servos eine Obergrenze, wie lange die Pause sein darf. Aber wie gesagt: das sind spezielle Servos, die noch dazu meistens schweineteuer sind. Eher unwahrscheinlich, dass du solche hast.
>Die Schaltung ist zwar nicht optimal, aber auch kein Beiunbruch. >Du hast minimal 1ms Zeit, alle Register mit dem gewünschten nächten >Bitmuster zu laden. Das ist bequem zu wuppen. Sorry, aber ich kann dir grad nicht folgen. Hast du den Nerv mir das an nem Beispiel zu erklären? (z.B. Ausgangssituation: Pulsdauer Motor1: 1,2 ms ; Motor5: 1,35 ms ; Motor 11: 2,0 ms) >Die 20ms Pausendauer sind ein Minimalwert, länger stört nicht. Muss ich nicht innerhalb von 20 ms die Pulsweite an den Servo schicken?
idler schrieb: >>Die 20ms Pausendauer sind ein Minimalwert, länger stört nicht. > > Muss ich nicht innerhalb von 20 ms die Pulsweite an den Servo schicken? Zum Hundertausendsten mal: NEIN! (Ich weiß nicht, wie oft dir hier verschiedene Leute in diesem Thread schon gesagt haben: Kleb nicht an den 20ms. Die sind irrelevant und haben historische Ursachen und interessieren die Servos nicht im geringsten)
Sorry Karl heinz, zu spät gelesen. Also es sind analoge Servos, Hitec HS-645MG also du meinst in der Regel machen 40 ms - 60 ms dazwischen auch nix aus?
idler schrieb: > (z.B. Ausgangssituation: Pulsdauer Motor1: 1,2 ms ; Motor5: 1,35 ms ; > Motor 11: 2,0 ms) - Motor1 = 1, alle anderen 0, Timer auf 1.2ms - Motor5 = 1, alle anderen 0, Timer auf 1.35ms - Motor11 = 1, alle anderen 0, Timer auf 2.0ms ... Peter
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.