Ansteuern eines Hobby-Servos mit einem Arduino

Ansteuerung eines Hobby-Servos mit einem Arduino

Wir steuern ein Hobby-Servo mit einem Arduino (AVR)-Mikrocontroller, indem wir ein PWM-Signal (Pulsweitenmodulation) vom Mikrocontroller an das Servo ausgeben. Wir werden einen Großteil der Informationen aus dem vorherigen Video und den Informationen zu den Grundlagen der PWM verwenden. Wir werden auch einige neue Fachbegriffe lernen, die spezifisch für Arduino-Mikrocontroller sind.

Zuerst müssen wir einen Timer und den richtigen WGM (Waveform Generation Mode) innerhalb dieses Timers auswählen, der für das Servo geeignet ist. Als Nächstes müssen wir die PWM-Periode auswählen, die mit dem Servo funktioniert. Das im Video verwendete Servo akzeptiert eine Periode von 20 Millisekunden, und wir werden das ICR1-Register nutzen, um diese Periode zu erzeugen. Dazu müssen wir einen Prescaler bestimmen, damit der Timer die Taktrate des Mikrocontrollers richtig nutzt, wir müssen die PWM in den richtigen Modus einstellen, invertiert oder nicht-invertiert, wobei der Puls am Anfang der Periode oder am Ende der Periode stattfindet, und schließlich müssen wir bestimmen, welches OCR (Output Capture Register) wir verwenden, 1A oder 1B.

Darstellung einer phasenkorrekten PWM mit Timer-Zähler und dem PWM-Signal Darstellung einer schnellen PWM mit Timer-Zähler und dem PWM-Signal

Zuerst wollen wir die WGM (Waveform Generation Modes) im Arduino bestimmen. Es gibt zwei Haupttypen von Wellenformgenerierungsmodi, die schnelle PWM und die phasenkorrekte PWM, wie wir sie im vorherigen Video kennengelernt haben. Die phasenkorrekte PWM erzeugt den Puls in der Mitte der Periode. Wie geschieht das? Im phasenkorrekten Modus zählt der Arduino-Timer hoch und dann wieder herunter. Zu Beginn der Periode (wenn der Timerzähler auf 0 steht) zählt der Timer bis zu einer eingestellten Zahl, die Sie im Arduino-Register (ICR1) speichern, oder lassen Sie den Timer bis zum Maximalwert einer 8-Bit-, 9-Bit- oder 10-Bit-Zahl zählen, was 256, 512 bzw. 1024 ist. Während der Timer bis zu dieser von Ihnen festgelegten Maximalzahl zählt, stellen Sie ein anderes Register ein, um einen Pin hochzuschalten (den Pin, der das PWM-Signal ausgibt), wenn er eine bestimmte Timerzahl erreicht. Diese Timerzahl wird zweimal erreicht, da der Timer hochzählt und dann, wenn er das Maximum erreicht, wieder herunterzählt. Wenn der Timer dieselbe Zahl erreicht, während er herunterzählt, geht der PWM-Pin auf Low. Sie können auch jeden Pin so einstellen, dass er ein PWM-Signal ausgibt, da Sie immer Zugriff auf den Timerzähler haben und bereits wissen, wie man einen Pin auf High und Low setzt.

Dann gibt es die schnelle PWM, bei der der Timer hochzählt und dann auf 0 zurückgesetzt wird, wenn er den gewünschten maximalen Zählwert erreicht, den Sie eingestellt haben. Der Timer zählt bei schneller PWM nicht wieder herunter, sondern wird einfach auf 0 zurückgesetzt und beginnt dann wieder hochzuzählen. Der Puls des PWM-Signals tritt am Anfang oder am Ende der Periode auf, je nachdem, ob Sie sich im invertierten oder nicht-invertierten Modus befinden. So wird der Puls im schnellen PWM-Modus geformt. Im nicht-invertierten Modus stellen Sie einen bestimmten Wert für den Timer ein, damit das PWM-Signal hoch geht. Wenn der Timer 0 ist, ist das PWM-Signal niedrig; wenn der Timer den eingestellten Wert erreicht, ist die PWM hoch, bis der Timer wieder auf 0 geht.

In diesem speziellen Beispiel im Video verwende ich den ICR1, um das obere Ende des Timer-Zählers einzustellen, und ich verwende auch Fast PWM (WGM13, WGM12 und WGM11 sind in den Timer-Counter-Control-Registern TCCR1A und TCCR1B eingestellt). Das Servo benötigt keine phasenkorrekte PWM. Das einfache Setzen dieses Registers auf einen gewünschten Maximalwert zwingt den Timer dazu, auf 0 zurückzusetzen, wenn diese Zahl erreicht ist. Dadurch wird unsere Periode erzeugt.

TCCR1A |= 1< TCCR1B |= 1<

Das von mir verwendete Hobby-Servo benötigt ein 50-Hz-Signal. Was bedeutet das? Das Servo benötigt ein PWM-Signal, das 50 Mal pro Sekunde auftritt. Welchem Anteil einer Sekunde entspricht 50 Hz? Wenn wir eine Sekunde durch 50 teilen, erhalten wir 1/50 = 0,02 Sekunden. Das ist das Gleiche wie 2 Dezisekunden oder 20 Millisekunden (ms). Dezisekunden werden im Allgemeinen nicht verwendet, aber Millisekunden (ms) schon. Wir müssen also alle 20 (ms) einen Puls senden, was bedeutet, dass unsere Periode 20 ms lang sein muss, und der Puls innerhalb dieser 20-ms-Periode stattfinden wird.

Jetzt müssen wir den maximalen Timer-Zähler bestimmen. Um herauszufinden, was 20 ms für unseren Timer bedeutet, müssen wir die Taktrate des Mikrocontrollers berücksichtigen, da der Timer mit den Taktzyklen läuft. Bei jedem Taktzähler zählt der Timer hoch. Wenn der Mikrocontroller auf 1 MHz oder 1.000.000 Hz eingestellt ist, können wir bestimmen, dass der maximale Timer-Zähler 1.000.000/50Hz betragen müsste, was 20.000 ist. Also kann der ICR1 auf 19.999 eingestellt werden, da das Zählen bei 0 und nicht bei 1 beginnt. Wenn Sie eine andere Taktrate haben, sagen wir 16.000.000, dann verwenden Sie einfach den F_CPU-Wert in einer Formel, wie F_CPU/50, und Sie erhalten Ihre ICR1-Nummer. Aber halt, was ist, wenn die Zahl größer ist als 65.535, was die maximale erlaubte Zahl für den Timer ist? Hier benötigen Sie einen Prescaler für den Timer, der die Bits CS10..12 ist. Da wir keinen Prescaler benötigen, müssen wir nur das Bit CS10 im TCCR1B-Register setzen.

ICR1 = F_CPU / (Servo acceptable Hz value); //Verwenden Sie einen Prescaler, wenn der ICR1 einen Wert über 65535 hat

Wir werden für dieses Beispiel den invertierten Modus verwenden, der das PWM-Signal bei Timer-Zähler 0 auf Low setzt. Der OCR1A ist der Wert, an dem wir den Puls starten lassen werden. Der OCR1A hat einen Wert innerhalb des Maximums von 19.999. Um den invertierten Modus einzustellen, müssen wir die Bits COM1A1 und COM1A0 im TCCR1A-Register setzen. Wenn wir den nicht-invertierten Modus verwenden wollten, müsste COM1A1 gesetzt werden, aber COM1A0 müsste nicht gesetzt werden. Ach ja, wenn Sie OCR1B anstelle von OCR1A verwenden wollten, müssten Sie einfach COM1B1 und COM1B0 verwenden.

TCCR1A |= 1<

Da wir im Beispiel den invertierten Modus verwenden, müsste der OCR1A-Wert 19.999 abzüglich der tatsächlichen Pulsbreite (gemessen an der Anzahl der Timer-Zählzyklen) sein, da der Puls am Ende der Periode liegt. Zum Beispiel, wenn die Pulsbreite 2 ms beträgt, wären dies 2000 Timer-Zyklen. Der OCR1A-Wert ist also 19.999 - 2000 = 17.999.

OCR1A = ICR1 - (Pulse Width);

Bild des auf dem Breadboard aufgebauten Schaltkreises mit dem angeschlossenen ServoDas Servo ist an den Schaltkreis (Breadboard) angeschlossen, wobei die Stromversorgung (rotes Kabel) an die + Schiene und GND (schwarzes Kabel) an die - Schiene geht. Das Signalkabel des Servos, das gelbe Kabel, ist an den OCR1A-Pin angeschlossen, der Pin Nummer 19 am ATmega 32 ist. Sie müssen das Datenblatt Ihres Mikrocontrollers konsultieren, um den Speicherort des OC1A-Pins zu bestimmen, wenn Sie einen anderen Mikrocontroller verwenden.

Das folgende Programm stellt die Position des Servos auf die 2-ms-Rotationsmarke ein. Dies ist ein Maximum, das im Datenblatt angegeben ist, aber das Servo erreichte den 180-Grad-Winkel nicht. Möglicherweise müssen Sie die Zahlen anpassen, um so nah wie möglich an die Extreme Ihres Servos heranzukommen, aber gehen Sie nicht zu weit, sonst beschädigen Sie das Servo (Getriebe werden überdreht). Testen Sie die Rotation des Servos, indem Sie die OCR1A-Nummer innerhalb der minimalen und maximalen Spezifikationen des Datenblatts ändern. Mein Datenblatt gab 0,9 ms (900 Timer-Ticks) als Minimum an.

#include
int main(void)
{
DDRD |= 0xFF;
TCCR1A |= 1< TCCR1B |= 1< ICR1A = 19999;

OCR1A = ICR1 - 2000; //18000

while (1)
{
}
}

Lassen Sie uns etwas Spaß haben und das Servo ständig hin und her bewegen. Die Anweisungen müssen in der Endlosschleife stehen. Wir müssen eine Verzögerung hinzufügen. Wenn keine Verzögerung hinzugefügt würde, würde sich das Servo nicht bewegen und hier ist der Grund: Es dauert einige Zeit, bis sich das Servo in eine Position bewegt, da es sich um ein mechanisches Gerät handelt. Im Video können Sie sehen, dass das Servo etwa ein Zehntel einer Sekunde brauchte, um von einem Rotationswinkel zum anderen zu gelangen. Die Anweisungen brauchen eine Millionstel Sekunde, um eine Anweisung auszuführen, und das Servo könnte in diesem Zeitrahmen nicht einmal einen Bruchteil der Rotation bewegen. Wir müssen also eine Zeitverzögerung zwischen jeder Einstellung der Position des Hebels einführen.

#include
#include
int main(void)
{
DDRD |= 0xFF;
TCCR1A |= 1< TCCR1B |= 1< ICR1A = 19999;

OCR1A = ICR1 - 2000; //18000

while (1)
{
OCR1A = ICR1 - 800;
_delay_ms(100);
OCR1A = ICR1 - 2200;
_delay_ms(100);
}
}
Zurück zum Blog

Hinterlasse einen Kommentar

Bitte beachte, dass Kommentare vor der Veröffentlichung freigegeben werden müssen.