Hallo,
Ich muss fuer ein Schulprojekt Servos ueber den Timer meines Atmega16's
ansteuern.
Ich habe bereits versucht ein entsprechendes Programm zu schreiben, aber
das Servo zuckt nur hin und her.
Warscheinlich habe ich nur einen Denkfehler in meinem Code ,aber ich
finde ihn selbst nicht.
Hier der Teil des Codes:
Der Codefetzen ist nicht ausreichend, um das Problem endgültig zu lösen.
> 2000000/255(timer) =7843,137255 (eine sekunde)
Die 255 sind falsch, hier ist nicht der Topwert des Zählers gefragt. Das
müssen 256 sein, nämlich die Anzahl Schritte. Die 255 hast du noch
paarmal falsch verwendet.
Aber was anderes... der Atmega16 hat doch einen CTC Modus beim Timer0.
Richte den so ein, dass du eine Uhr bekommst, die im 2ms Abstand tickt
(Prescaler 256, OCR0 124). Damit kannst du deine 2ms AN-Zeiten machen
und deine 20ms AUS-Zeiten (Softwarezähler 10x2ms).
Alternativ kannst du eine PWM einrichten mit 1:10 Duty Cycle und 22ms
Frequenz.
Ich benutze ausserdem das STK500 zum programmieren und auf meiner
Schaltung einen 16Mhz Oszillator.
Ob der Timer bis 255 oder bis 256 zaehlt wusste ich nicht mehr genau ,
mit 256 hat es allerdings bisher auch nicht geklappt.
Das servo soll sich spaeter auch in andere Richtungen bewegen , die 2 ms
sind nur als Beispielprogrammierung gedacht.
Vielen Dank schonmal!
Hast du Unterlagen oder einen Link vom Servo, wie der anzusteuern ist?
Es hilft enorm, wenn du die Rechenvorschrift zuerst in eigenen Worten
formulierst und dann erst anfängst das in Programmcode umzusetzen.
Max G. schrieb:
> ...>> Ich benutze ausserdem das STK500 zum programmieren und auf meiner> Schaltung einen 16Mhz Oszillator.>> Ob der Timer bis 255 oder bis 256 zaehlt wusste ich nicht mehr genau ,> mit 256 hat es allerdings bisher auch nicht geklappt.
Von 0-255
> Das servo soll sich spaeter auch in andere Richtungen bewegen , die 2 ms
Dann wäre aber unabhängig von allem anderen 1.5ms ein guter Wert also
die theoretische Mittelstellung, ob der Servo funktioniert merkt man
dann daran, dass er die Position unter Gegenkraft hält.
> sind nur als Beispielprogrammierung gedacht.>> Vielen Dank schonmal!
Jetzt kommt es allerdings noch darauf an, wieviele Servos du steuern
musst/willst, es gibt hier im Forum und auch auf avrfreaks.net,
(Anmeldung erforderlich), Beispiele bei denen bis zu 20 Servos von einem
Controller gesteuert werden. Wenn du jetzt aber nur 2 Servos hochpräzise
(16Bit-Timer) und bis zu 4 weitere Servos weniger präzise (8Bit-Timer)
steuern willst, ist die obereleganteste Methode dazu die PWM. Mit der
16Bit-Timer-PWM läßt sich der Servo rein uC-technisch mit mehr als 1000
Einzelschritten ansteuern also z.B. 180 Grad / 1000Schritte = 0,18 Grad
pro Schritt. Das Beste daran ist, dass die PWM völlig unabhängig vom
restlichen Programm läuft und auch keine Interrupts benötigt, man kann
einfach wann immer man will neue Positionswerte für den Servo in ein
Register schreiben und der Servo rennt los zur neuen Position.
Programmcode sind das nur wenige Zeilen (< 10) für die Initialisierung
der PWM. Die einzige Hürde besteht darin sich die Timer-Sektion im
Datenblatt durchzulesen UND zu verstehen, und ich weise gleich darauf
hin, dass man dazu mehrmals vor- und zurückblättern muss, es steht
nämlich definitiv nicht alles auf einer Seite. Und man braucht auch
nicht zu versuchen die einzelnen PWM-Modi irgendwie logisch herzuleiten,
die sind einfach so gegeben. Man schaut sich an was es da gibt und wählt
dann einen aus. Für erste Versuche, empfiehlt sich z.B. WGM-Mode "14"
(FastPWM), in diesem Mode wird die Grundfrequenz der PWM, (20ms, 50Hz)
durch ICR1 festgelegt und die Länge der einzelnen (Servo)-Pulse, (1ms -
2ms), durch Einträge in OCR1B oder OCR1A, die Steuerausgänge für die
(zwei) Servos sind dann beim ATmega16 an Pin 18 und 19, (ja, die heißen
so ähnlich nämlich OC1B und OC1A, das sind aber die Pins und nicht die
Register).
Also:
1. Steuerpins für die Servos auf Ausgang.
2. WGM-Mode einstellen, z.B. Mode "14"-FastPWM, (Die WGM-Bits sind auf
zwei Register verteilt!)
3. CompareMatch Mode einstellen, (z.B.: Set OCnA/OCnB on Compare Match,
Clear OCnA/OCnB, Non-Inverting-Mode (1,0))
4. ICR1 mit der Grundfrequenz laden, (z.B. 20000 für 50Hz, (bei
entsprechendem Prescaler und Taktfrequenz)).
5. Prescaler nicht vergessen, (bei einer Taktfrequenz von z.B. 8MHz und
einem Prescaler von "8", kann man die PVM direkt ohne Umrechnungen mit
Mikrosekunden "füttern", d.h. ein 1500 in OCR1B oder OCR1A geschrieben
bewegt den Servo in Mittelposition).
Das Setzen des Prescalers startet die PWM.
6. In OCR1B oder OCR1A, (je nachdem wo der Servo angeschlossen ist), den
gewünschten Positionswert schreiben.
die gemachten Vorschläge solltest du dir IMHO gut anhören, und es gibt
an vielen Stellen auch viele Beispielcodes. Basierend auf deinem
Beispiel verstehe ich nicht wozu du TCNT0 explizit setzt, vielleicht
klappt es so
volatile unsigned char servo_pulse_length= 12 //12 = 1.536ms
ISR(TIMER0_OVF_vect) //is called every 0.128 ms
{
static unsigned char timer_count;
static unsigned char pulse;
timer_count++;
if( pulse ){
if( timer_count>=servo_pulse_length ){
pulse= 0;
timer_count= 0;
PORTB &=~(1<<PIN2); // Servo puls aus
}
}else{
if( timer_count>=156-servo_pulse_length ){ //156 = 19.968ms
pulse= 1;
timer_count= 0;
PORTB |=(1<<PIN2); // Servo puls an
}
}
}
hat so keine sehr hohe Auflösung, wenn du den Prescaler 1 setzt, und
statt char dann einige int nimmst, bekommst du schon für viele Zwecke
mehr als ausreichend Auflösung
have fun, Olli
Kleine Verwirrung, das wäre ein passender Mode:
3. CompareMatch Mode einstellen, (Clear OC1A/OC1B on compare match, set
OC1A/OC1B at BOTTOM, (non-inverting mode) (1,0))
Danke fuer die Vielen Antworten!
Ich denke ich werde es mit PWM probieren , allerdings habe ich da schon
wieder die naechste Frage.
Ich habe mich schonmal theoretisch ueber die PWM Programmierung
informiert, allerdings leuchtet mir nicht ein wie ich den Vergleichswert
in OCR1A setzen muss damit ich die gewuenschte Frequenz erhalte.
Mit freundlichen Gruessen!
Max G. schrieb:
> Ich habe mich schonmal theoretisch ueber die PWM Programmierung> informiert, allerdings leuchtet mir nicht ein wie ich den Vergleichswert> in OCR1A setzen muss damit ich die gewuenschte Frequenz erhalte.
Dann wirds Zeit, dass du dir klar machst, wie das Ganze auf
Hardwareebene eigentlich funktioniert.
Da ist ein Timer.
Der zählt ständig
0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1
Immer wenn er bei 0 ist, macht er etwas. zb einen Pin auf High setzen.
Wie oft macht er das in einer Sekunde?
Das hängt ganz offensichtlich davon ab, wie schnell der Timer zählt und
es hängt auch davon ab, ob er bis 8 oder nur bis 4 zählt.
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1
Jetzt kommt die 0 im selben Zeitraum öfter, weil der Timer ja nicht so
weit hochzählt.
Wie schnell zählt denn jetzt der Timer (unabhängig davon wie weit er
zählt)?
Der Timer hängt am Systemtakt (also an deinem Quarz mit dem auch der
Rest des µC versorgt wird). Ist der 16Mhz dann macht der Timer 16
Millionen Zählvorgänge in der Sekunde, isr der 12Mhz dann eben 12
Million, ist der 3.768Mhz dann eben 3.768 Millionen.
Da das ziemlich viel ist, gibt es den Vorteiler. Der Vorteiler teilt die
Systemfrequenz durch einen einstellbaren Faktor runter. Ist der
Vorteiler 8 und der Systemtakt 16Mhz, dann macht der Timer nur 16/8 = 2
Millionen Zählvorgänge in der Sekunde.
Jetzt interessieren uns ja nicht die Anzahl der Zählvorgänge sondern uns
interessiert, wie oft dabei die 0 vorkommt.
Wenn der Timer also in 1 Sekunde bis 2 Millionen zählt UND er jedesmal
bis 8 zählt (das sind 9 Zählvorgänge, auf die 0 nicht vergessen!) dann
kommt die 0 genau 2000000 / 9 = 222222.222 mal vor. Schaltet man bei
jeder 0 einen Pin ein und bei einem anderen Zählerstand wieder aus, dann
hat man daher eine Frequenz von 222222.222Hz oder knapp 222kHz.
Lässt man den Timer nicht bis 8 sondern bis 138 zählen und verändert
sonst nichts, dann beträgt diese Frequenz 2000000 / 139 = 14388.49Hz
also schon bedeutend weniger.
Und, Überraschung, das wars. Das ist alles was man wissen muss um zu
verstehen, wie man eine bestimmte Frequenz mit einem Timer erzeugen
kann.
Die Freuqenz ergibt sich aus:
Systemfrequenz, Vorteiler und wie weit der Timer zählen muss. Die
Systemfrequenz kannst du meistens nicht mehr beeinflussen, die ist
vorgegeben. Aber an den beiden Parameter Vorteiler und Höchstwert kann
man drehen, bis man die gewünschte Frequenz erreicht hat.
Max G. schrieb:
> ...> Ich habe mich schonmal theoretisch ueber die PWM Programmierung> informiert, allerdings leuchtet mir nicht ein wie ich den Vergleichswert> in OCR1A setzen muss damit ich die gewuenschte Frequenz erhalte.
Also wenn du dich auf meine Ausführungen beziehst, dann: Gar nicht!
Bei den von mir vorgeschlagenen Modi hat OCR1B bzw. OCR1A überhaupt
nichts mit der Frequenz sondern nur mit der PULSWEITE zu tun, (für die
Frequenz ist ICR1 zuständig).
Wenn du jeden Tag in die Schule gehen würdest, dann wäre die Frequenz
deiner Schulbesuche:
f = 365 / 1_Jahr_in_Sekunden
oder auch:
f = 7 / 1_Woche_in_Sekunden
Das sagt etwas über Häufigkeit aus mit der ein Ereignis stattfindet,
also wie oft du in die Schule gehst. Damit ist aber noch immer völlig
unklar WIE LANGE du jeden Tag in die Schule gehst. Kann ja sein, dass du
da jeden Tag immer bloß kurz "Hallo" sagst und dann gleich wieder
abhaust. Oder das andere Extrem, dass du da jeden Tag 23h 59m 59s
verbringst.
Die Pulsweitenmodulation besteht also aus zwei Komponenten:
1. Der Häufigkeit, mit der ein Ereignis stattfindet, (das wären beim
(Standard)-Servo unveränderlich alle 20ms ein Puls, also 50 mal pro
Sekunde -> 50Hz).
und
2. Der Dauer, die angibt wie lange das Ereignis andauert, (das wäre beim
Servo die Dauer des Steuer-Pulses, die ist veränderlich und soll je nach
gewünschter Position zwischen 1ms bis 2ms dauern).
Warum der Servo, wenn er alle 20ms ein Signal mit einer Dauer von 1ms
bis 2ms erhält, in ein bestimmte Position fährt ist natürlich eine ganz
andere Frage.
Bei den von mir vorgeschlagenen Einstellungen:
"WGM-Mode-14-FastPWM"
-> Dafür entsprechende Bits in TCCR1B und TCCR1A setzen.
+
"(1,0) Clear OC1A/OC1B on compare match, set
OC1A/OC1B at BOTTOM, (non-inverting mode)"
-> Dafür entsprechende Bits in TCCR1A setzen.
legt nun der Wert im Register "ICR1" die (von uns so gewünscht
unveränderliche) Frequenz der PWM fest. Wohingegen Einträge in "OCR1B"
und/oder "OCR1A" die Dauer/Länge der Pulse, die die PWM ausgibt,
festlegen.
Die Werte die nun tatsächlich in "ICR1", "OCR1B" und/oder "OCR1A"
eingetragen werden müssen, hängen ausschließlich von der Taktfrequenz
des Mikrocontrollers und dem eingestellten Vorteiler "Prescaler" ab.
Ok, schauen wir mal bei 16 MHz:
Wir brauchen eine Frequenz von 50 Hz, (der Timer soll dabei aber immer
noch so fein einstellbar sein, dass er zusätzlich auch noch Zeiten
zwischen 1ms und 2ms in ausreichend kleinen Schritten darstellen kann).
Und wie fängt man da an? Einfach mal 16MHz durch 50Hz teilen? Warum
nicht, kann ja nicht schaden ...:
16000000Hz / 50Hz = 320000
Was bedeutet das? Nun, nicht viel, nur dass nach jeweils 320000
Taktzyklen 20ms vergangen sind und dass das 50 mal in der Sekunde
geschieht.
Wir sollten also irgendwie 320000 Taktzyklen abzählen können. Bisschen
blöd auf einem 8Bit-uC, da wird meist nur von 0-255 gezählt, aber auch
16Bit helfen nicht richtig weiter (0-65535)...
Programmiertechnisch und vor allem in C würde das Zählen mit ein paar
großen Variablen natürlich schon gehen, aber das ganze soll ja ohne
Spezial-Programm nur mit den Möglichkeiten der ATmega-Timer im
Hintergrund ablaufen.
Aber Moment, da gibt es ja noch den Prescaler. Der Prescaler ist sehr
einfach aufgebaut, da gibt es nicht viele Möglichkeiten, nämlich nur
Teiler von: 0, 1, 8, 64, 256 und 1024.
Nehmen wir mal 8 ;-), da sieht die Rechnung schon etwas handlicher aus:
(16000000Hz / 8) / 50Hz = 40000
Na immerhin, das passt ja schon mal in ein 16Bit Register. Super Sache,
wenn wir also den Prescaler auf 8 setzen und den Wert 40000 in ICR1
schreiben, (und ICR1 ist zufälligerweise ein 16Bit-Register), dann läuft
die PWM konstant mit 50Hz.
Bleibt noch die Pulsdauer, (also der Wert der in OCR1B und/oder OCR1A
geschrieben werden muss um die Position des Servos festzulegen). Das ist
jetzt einfach, wir wissen ja bereits, dass ein (Timer)-Wert von 40000
genau 20ms entspricht.
Wieviele (vorgeteilte) Takte müssen es dann für 1ms, 1.5ms, 2ms, 1/10ms
oder 1/100ms sein?
40000 / 20ms = 2000 (Timertakte für 1ms)
->
Timerwert 2000 ~ 1ms Pulsdauer
Timerwert 200 ~ 1/10 ms Pulsdauer
Timerwert 20 ~ 1/100 ms Pulsdauer
Timerwert 2 ~ 1/1000 ms Pulsdauer
Timerwert 1 ~ 1/2000 ms Pulsdauer
Bekannte Werte für ein Servo sind ja nun:
1.0 ms = ganz links (je nachdem von wo man draufschaut)
1.5 ms = Mittelstellung
2.0 ms = ganz rechts
also:
Timerwert 2000 = ganz links
Timerwert 3000 = Mittelstellung
Timerwert 4000 = ganz rechts
Und halt alles was dazwischen liegt.
Ergänzung:
Ja, es gibt auch PWM Modi bei denen die Frequenz mit OCR1A festgelegt
wird.
Und: In der Praxis können die Werte für Servoausschlag "ganz links" und
Servoausschlag "ganz rechts" um einiges von den Idealwerten 1,0ms bzw.
2.0ms abweichen, also darunter bzw. darüber liegen.
Darauf achten, dass nicht schon in den Fuses ein Taktvorteiler aktiviert
ist und überhaupt mit den Fuses sicherstellen, dass der Controller auch
tatsächlich mit dem gewünschten Takt läuft.
Wow, danke fuer die Ausfuehrliche Hilfe!
@Albrecht H.
Ich hab es mal nach deiner Beschreibung versucht und fand das auch alles
recht einleuchtend , aber funktionieren tut es leider trotzdem noch
nicht.
Hier ist das Programm das ich bis jetzt verfasst habe:
Na ja, ..., also das ist jetzt für den ATmega644p, kompiliert aber auch
für den ATmega16 und die Pinbelegung sollte zumindest für OC1B auch die
selbe sein, probiers mal aus.
Die Tastenabfrage mit den langen Delays ist nur für Testzwecke gedacht
und ansonsten ein Beispiel dafür, wie man es nicht machen sollte.
Vielen Danke, es funktiniert !! :D
Zumindest eingeschraenkt ;)
Bei jedem zweiten Einschalten zuckt das Servo einfach nur ohne sich an
die Stelle zu begeben die programmiert wurde.
Woran koennte das liegen ?
Auch das andere Servo , das ich zwar an den Atmega angeschlossen habe ,
allerdings noch nicht programmiert, zuckt.
Mit freundlichen Gruessen!
Max G. schrieb:
> Vielen Danke, es funktiniert !! :D> Zumindest eingeschraenkt ;)> Bei jedem zweiten Einschalten zuckt das Servo einfach nur ohne sich an> die Stelle zu begeben die programmiert wurde.> Woran koennte das liegen ?
Gut, da müsste ich jetzt mal selbst einen ATmega16 ins Steckbrett
einsetzen, ich hab das vorher nur mit dem ATmega644p ausprobiert der
halbwegs Pin- und Registerkompatibel zum ATmega16 ist.
Ok, gesagt getan. Und im ersten Moment dachte ich: "Oh, da stimmt ja
tatsächlich was nicht!". Aber nein, Fehlalarm, es war nur die
"SUT_CKSEL"-Fuse falsch gesetzt, nämlich auf "RC Osc. 8.0 MHz..."
anstatt auf "Ext. Crystal/Resonator High Freq.;... 16K CK + 64 ms".
Danach funktionierte dann alles wie erwartet: Beim Einschalten der
Spannungsversorgung ruckelt der Servo kurz und fährt dann sofort in
Mittelposition, dann je nach Tastendruck, Links, Mitte, Rechts,
schrittweise vor und zurück ohne Zittern oder sonstwas.
Und woran könnte es nun bei dir liegen?
Da sehe ich in erster Linie zwei wahrscheinliche Ursachen:
Vorab:
Mach erstmal meine Tastenabfragen komplett raus! Vielleicht prellt da
was bei dir, darum kannst du dich aber später kümmern, (->
Artikelsammlung, Wiki, Peter Dannegger / Tastenentprellung).
Probier dann erst was einfaches aus wie, (zwischen den Delays noch eine
LED als zusätzliche Kontrolle ein und auszuschalten kann definitiv
hilfreich sein):
1
while(1){
2
3
_delay_ms(2000);
4
5
OCR1B=DefServoMidAbs;
6
7
_delay_ms(2000);
8
9
OCR1B=DefServoMinAbs;
10
11
_delay_ms(2000);
12
13
OCR1B=DefServoMaxAbs;
14
15
_delay_ms(2000);
16
17
}
Wenn es dann funktionuert lag es halt an den Tastern, (die werden in
meinem Beispiel übrigens gegen GND (-) geschaltet).
Falls nicht dann:
1. Deine Taktfrequenz stimmt nicht:
Fuses überprüfen, (für 16MHz mit externem Quarz -> "SUT_CKSEL" auf "Ext.
Crystal/Resonator High Freq.;... 16K CK + 64 ms")! Und wenn du ein
Entwicklungsboard wie das STK500 verwendest, nachschauen ob die Jumper
für den externen Quarz auch wirklich richtig gesetzt sind! Ich muss da
auch selbst jedesmal im User Manual nachschauen, wie die richtige
Einstellung ist, wenn ich mal was geändert habe!
Dann die Frequenz an OC1B gegen Masse mit dem Oszilloskop nachprüfen!
Das müssen 50Hz sein, diese Messung funktioniert sogar mit meinem
billigen Multimeter (UNI-T), mit Frequenzmessbereich.
2. Der Hardwareaufbau:
Also allzu schwierig kann es eigentlich nicht sein, der Aufbau
funktioniert bei mir problemlos auf einem Steckbrett. Trotzdem sind
16MHz natürlich etwas kritischer als 8MHz, (die ich aus nostalgischen
Gründen öfter mal verwende).
Sind der Quarz und die zwei 22pF (oder 15pF) Kondensatoren so nah als
möglich an den entsprechenden Prozessorpins?
Reset über 10K an (+), und mit 100nF an Masse?
Sind überall (VCC/GND) 100nF Abblock/Überbrückungs-Kondensatoren
eingesetzt?
Ist die Spannungsversorgung stabil? Läuft die Schaltung mit 5V?
Bekommt der Servo genügend Strom? Die Spannungsversorgung sollte zum
Testen am unbelasteten Servo mindestens 2A liefern können ohne
einzubrechen!
Saubere Kontake, kurze Verbindungsleitungen, blabla, ...
> Auch das andere Servo , das ich zwar an den Atmega angeschlossen habe ,> allerdings noch nicht programmiert, zuckt.> Mit freundlichen Gruessen!
Nachtrag:
Ich hab gerade nochmal ein paar Servos "wild" drehen lassen auch unter
Last und mit Blockieren, ein Mikroservo hat dabei sogar seine Sperre
durchbrochen und kreiselte dann nur noch. Also die können schon in die
Mikrocontrollerschaltung einstreuen, wenn man es darauf anlegt, entweder
über die gemeinsame Versorgungsleitung oder möglicherweise auch über den
Steuereingang. Es ist mir auch ein paar mal gelungen das Programm in
einen undefinierten Zustand zu bringen u.a. in dem ich einen üblen
Wackelkontakt an der gemeinsamen Versorgungsleitung simulierte, ein
zusätzlich angeschlossenes LCD kam auch mehrmals aus dem Takt und
stellte die Wiedergabe ein.
Subjektiv hatte ich dabei den Eindruck, dass die Schaltung mit meinem
alten ATmega16 mit 16MHz Quarz störanfälliger war als mit einem 8MHz
Quarz und insgesamt störanfälliger als dieselbe Schaltung mit einem
neuen ATmega644p.
Der ATmega644p war mit 8MHz kaum aus dem Takt zu bringen und startete
höchstens mal neu über die Brownout-Detection wenn man es zu bunt trieb.
Es sind also u.U. noch ein paar Einstörmaßnahmen erforderlich ...,
(Kondensatoren, Drosseln, Dioden?).
Ich erinnere mich, sowas auch mal mit einem 8051 aufgebaut zu haben, da
hatte ich von vornherein, getrennte Spannungsversorgungen für uC und
Servo verwendet und das ganze über einen Optokoppler zusammengeschaltet,
aber ob das wirklich notwendig ist ...
Vorbildlich verhielt sich übrigens ein vergleichsweise teures
Graupner-Digitalservo im roten Aluminiumgehäuse.
So, nachdem ich letzte Woche einiges um die Ohren hatte ,konnte ich mich
gestern wieder dem Projekt widmen. Ich habe einfach die Servos durch
zwei neue ersetzt und jetzt funktioniert alles wunderbar, die Servos
bewegen sich an die Stelle die programmiert ist und bleiben dort. :)
Vielen Dank an alle die mir hier geantwortet haben ! :D
Hi, ich habe diesen Beitrag hier grade gefunden, und hänge auch mit
meinem Servo-Program:
Ich möchste allerdings nicht die OCR-Pins benutzen, sondern in der
Interrupt-Routine selbst nach einander die Pins von PortB ansteuern.
Ich benutze dazu den Fast-PWM Mode 14.
Quarz ist extern 14,76MHz.
Bei einem Prescaler von 8 ergibt sich dann ein Increment (also eine
256tel ms) von 7.
Die Idee ist nun, die 2ms Gesamtlänge mit dem ICR1 zu realisieren (ICR1
= 2 INCREMENT 256 = 3584), die Pulsbreite mit dem OCR1A = ((256 +
Sollwert) * INCREMENT).
Benutzt wird dazu das TIMER1_COMPA Interrupt.
1
ISR(TIMER1_COMPA_vect)
2
{
3
static uint8_t phase;
4
5
if(phase)
6
{
7
phase = 0;
8
PORT_SERVO |= (servos_used);
9
OCR1A = (INCREMENT * (ONE_MS + servodata[0]));
10
}
11
else
12
{
13
phase = 1;
14
PORT_SERVO &= ~(servos_used); //Alle Servo-Pins auf 0
TIMSK |= (1 << OCIE1A); //Compare Match OCR1A Enabled
7
ICR1 = (2* ONE_MS * INCREMENT);//Timer Top Value auf 2ms setzen
8
}
Ich versteh nicht, warum das Timing nicht stimmt. Habe schon mit allen
möglichen Modi rumgespielt und komme jetzt nicht mehr weiter. Seht Ihr
da was auf Anhieb?
1000*PRESCALER*RESOLUTION
ergibt einen satten Overflow
1000 ist ein int
PRESCALER (mit dem Zahlenwert 1) ist ein int
RESOLUTION (mit dem Zahlenwert 256) ist ein int
Also werden die Multiplikationen als int-Multiplikationen gemacht.
Das Ergebnis, 256000, passt aber nicht mehr in einen int -> Boing!
Fazit:
Gerade bei mathematischen Ausdrücken in Makros haben ein paar Klammern
noch nie geschadet. Das vermeidet unliebsame Überraschungen bei der
textuellen Substitution
Phillip Hommel schrieb:> immernoch eine Warning "Integer Overflow in Expression", obwohl der Erg.> ja mit 44064 eigentlich in das Int reinpassen sollte oder?
Ähm. 44064 passt in einen 16 Bit int nicht mehr rein.
Ich hoffe ich werde nicht der Leichenschändung gestraft für die Aktion..
Ich konnte den Code von Albrecht H. (alieninside) nicht nur verstehen
sondern auch wunderbar an meinen ATmega88 mit 8MHz anpassen 2 Servos
bzw. 2 Brushlessmotoren mit Regler lassen sich Einwand frei ansteuern.
mein Problem ist ich würder gerne 4 Motorensteuern ich dachte ich könnte
einfach OC0A und OC0B mit dazu ziehen stehe aber inzwischen wieder im
nirgendwo
hat jemensch nen Tipp?!
Danke an Albrecht H. (alieninside) für die Super erklärung mit Frequenz
und Zählzeiten etc. endlich hab ich das geraft
Robert M. schrieb:> Ich hoffe ich werde nicht der Leichenschändung gestraft für die Aktion..> mein Problem ist ich würder gerne 4 Motorensteuern ich dachte ich könnte> einfach OC0A und OC0B mit dazu ziehen stehe aber inzwischen wieder im> nirgendwo
Mach 'nen eigenen thread auf.
> hat jemensch nen Tipp?!
Poste was du an Programm schon hast, eventuell Schaltplan aber
mindestens die Anschlüsse zu den "Motoren" (hier geht es um
Modellbauservos) und beschreibe was du mit "OC0A und OC0B mit
dazuziehen" meinst. So weiß man ja noch nicht mal was (philharmony) hat
ohne sich in den ganzen thread einarbeiten zu müssen und du dann doch
irgendwas anderes gemacht hast.
Ok
Also ich will 4 Brushless Regler steuern die dann
(so zumindest der Plan) an OCR1A, OCR1B, OCR0A OCR0B hängen sollen.
Hier der angepasste Code von Albrecht