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
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 :-)
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
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 :-)
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.
>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