Hallo zusammen,
Habe ein kleines Problem beim verstehen der PWM/Timer0 des ATmega32u4.
Ich möchte einen Servomotor ansteuern mittels Timer0 (8-Bit) wobei die
PWM folgendermaßen aussieht:
1ms = 0° (Links)
1,5ms = 90° (Mitte)
2ms = 180°(Rechts)
Ich versteh nun nicht ganz wie genau ich mit der im Datenblatt
angegebenen Formel diese Zeiten/Stellungen am Servo bekomme.
fpwm = fcpu/(N*256)
Mit der obigen Formel weiß ich aber nicht ganz recht wie ich mein Ziel
erreichen soll.
Habe mir gedacht, dass OCR0B=0 Links entspricht und OCR0B=255 Rechts.
Wäre das richtig so?
Mein bisher programmierter Code dazu:
1
#include<stdio.h>
2
#include"dev/usb_serial.h"
3
#include<util/delay.h>
4
#include<avr/io.h>
5
#include"dev/adc.h"
6
#include<avr/interrupt.h>
7
8
9
10
intmain(void)
11
{
12
DDRD|=(1<<PORTD6);//Output
13
PORTD|=0x00;
14
15
TCCR0A|=((1<<COM0B1)|(1<<COM0B0)|(1<<WGM00)|(1<<WGM01));//COM: Set OC0B on Compare Match, clear OC0B at TOP / FAST PWM
16
17
TCCR0B|=((1<<CS00)|(1<<CS02));//Prescaler auf 1024
18
sei();
19
20
while(1)
21
{
22
if(pos<0)//pos soll später eine Variable sein welche von einem Joystick übergeben wird (-100 = Links / 0 = Mitte / 100 = Rechts)
Hallo,
überlege dir einmal wie PWM arbeitet. Dann überlegste dir oder spielst
einfach mal damit rum wie die PWM Timer Modi arbeiten. Dann wirst du
irgendwann darauf kommen, dass ein Wert die Frequenz bestimmt und der
zweite Wert das Duty Cycle. Funktionell nah an den Pulsen von Servo,
aber nicht dafür zugebrauchen. Mit Duty Cycle 0 haste Pulsweite 0%. Mit
Duty Cycle 255 haste Pulsweite 100%. Diese [%] Pulsweiten in Zeiten
umgerechnet sind abhängig der einstellten Timerfrequenz. Stichwort
Periodendauer.
Hallo,
Das mit der PWM verstehe ich soweit.
Nur wie bekomme ich meine 50Hz, also 20ms Periodendauer zusammen, mit
dem Prescaler und der obigen Formel bekomme ich min. 61Hz heraus, nicht
weniger.
So weit ich das verstanden habe, davon also von den 20ms Periodendauer
die ich haben möchte, den jeweiligen Prozentanteil, also 2ms sind dann
10% und eben 1ms sind 5%.
Ist das richtig so?
Danke für deine Antwort!
ersteinmal richtig, da Du aber schon erwähnst, das es nur 20% am einem
Anschlag und nur 5% am anderen Servoanschlag sind, brauchst Du natürlich
ordentlich Auflösung zwischen disen beiden Punkten. Du bekommst, selbst
wenn Du nur diese drei Stellungen, (links, mitte, rechts) benötigst,
dein Servo sonst nicht genau genug positioniert. Ob sich hierfür der
8-Bit Timer immernoch eignet?
Äxl
Danke für den Link!
Mein Problem ist Momentan dass ich nur den 8-Bit Timer (=Timer0)
verwenden kann. Laut meinem Programmier-Freund gibt es eine Lösung,
möchte er mir aber nicht verraten, ich soll selbst draufkommen.
Wenn ich einen 16MHz Clock habe und den Prescaler von 1024 verwenden
bekomme ich 15625. Das sind 0,064ms. Wenn ich auf die 20ms kommen möchte
kann ich hierbei jedoch max. 255 dazu multiplizieren, ergibt 16,32ms.
Rein logisch ginge sich das nie aus mit den 8-Bit, oder übersehe ich
hier etwas?
Hallo,
ich wette der Freund sucht selbst funktionierenden Code. :-)
Der verlinkte Code von hier gefällt mir persönlich nicht so richtig. Ich
erkläre dir mal meine Lösung. Das erfordert jedoch das du dich mit dem
Timer und Interrupt an sich schon beschäftigt hast. Du hast ein Servo
welches sich zwischen 0° und 180° bewegen kann. Wir nehmen mal an das
die 0° Position 1ms Pulsweite entsprechen und 180° Position 2ms
Pulsweite. Ich glaube es zwar nicht, aber das musst du wissen was dein
Servo kann. Spielt auch keine entscheidende Rolle, ist durch Umrechnung
alles anpassbar.
Jetzt möchtest du das Servo mit einer Auflösung von 1° bewegen. Was
bedeutet, du musst die 1ms Spielraum (2ms-1ms = 1ms) durch 180° teilen.
Das ergibt 5,55µs. Jetzt baust du dir einen Timer im CTC Mode, der aller
5,55µs seinen Compare Match ISR aufruft. Du suchst dir ein setup was nah
ran kommt. In der Timer ISR läuft ein Zähler. Mit dem regelst du deine
Pulsweiten von so vielen Servos wie du möchtest. Du weißt ja das ein
Inkrement des Zählers von ca. 5,55µs einem Grad Stellwinkel entsprechen.
Ich mach das so, dass ich immer bei Zähler 0 alle Servos einschalte und
dann nur noch den Zählerstand vergleiche mit der gewünschten
Servostellung und entsprechend das Servo abschalte. Damit erzeuge ich
die Pulsweiten. Dann warte ich ca. weitere 18ms und das Spiel geht von
vorn los. Als Feature schalte ich den Timer in den Pulspausen ab, damit
die "CPU Last" geringer ist.
Der "eigene Zähler" hat nichts mit irgendwelchen Timerregistern zu tun.
Der zählt nur im Zyklus der 5,55µs hoch. Nachdem die 20ms vorbei sind
oder nachdem die letzte Pulsweite fertig ist wird er genullt. Jetzt mach
daraus ... oder denkst dir eine noch bessere Lösung aus ... :-)
Ein Datalogger oder Oszi wäre auch nicht schlecht damit du siehst was du
machst bis es läuft.
Äxl (geloescht) schrieb:> Ob sich hierfür der 8-Bit Timer immernoch eignet?
Die 20ms Wiederholperiode ist völlig unkritisch, d.h. man kann mit dem 8
Bit Timer den 1..2ms Puls generieren und muss ihn nur ungefähr alle 20ms
anstoßen (Monoflop). Die Auflösung für die Position läge dann etwa um
1%.
Veit D. schrieb:> Ich mach das so, dass ich immer bei Zähler 0 alle Servos einschalte und> dann nur noch den Zählerstand vergleiche mit der gewünschten> Servostellung und entsprechend das Servo abschalte.
Man könnte die Servopulse auch nacheinander erzeugen und zum Schluss auf
20ms auffüllen. Dann sieht das so aus, wie es auch vom Fernsteuersender
kommt. Und wenn man nicht genügend IOs zur Verfügung hat, kann man das
Sinal an einem Pin ausgeben und es, wie in den klassischen Empfängern,
mit einem simplen Schieberegister dekodieren.
MfG Klaus