Archiv verlassen und diese Seite im Standarddesign anzeigen : servo pwm mit c erzeugen
JoSch1337
04.01.2008, 12:58
Hi!
Ich besitze ein rn-control board und habe bis jetzt vergeblich versucht ein sauberes pwm signal für einen servo und einen brushless controller zu erzeugen.
Beide verwenden wohl ein standard 20ms/50Hz pwm signal aber was ich bis jetzt gelesen habe deutet darauf hin, dass ich exakt dieses signal mit dem atmel wohl nicht erzeugen kann?
Hab bis jetzt die beiden hardware pwms genutzt und noch nichts in software probiert.
Gibt es eine gute hardware die ich zusammen mit rn-control nutzen kann um mir eventuelles hick hack in meiner software zu ersparen oder gibt es einen einfachen weg so einen standard pwm zu realisieren?
Jannemann
06.01.2008, 14:11
Hi JoSch,
also PWM mit 50Hz mit nem Atmel zu erzeugen geht wohl. Auf folgender Seite wird beschrieben, wie man es hinbekommt. http://mil.ufl.edu/~achamber/servoPWMfaq.html
Wichtig ist, dass du die richtigen Parameter(Register+Flags) setzt um deine gewünschte PWM Frequenz zu erhalten - die musst du natürlich selbst zusammenrechnen (je nach eingesetztem Quarz).
Bin aber auch erst frisch in dem Thema.
oberallgeier
06.01.2008, 14:48
... rn-control board ... pwm signal für einen servo ... Geht sicher problemlos für servos, zu brushless kann ich nix sagen (Erfahrung beschränkt sich auf die laufenden PC-Lüfter :) ),
... bis jetzt vergeblich versucht ein sauberes pwm signal ...Was heisst "sauber" ? ? ?
... rn-control board ... dass ich exakt dieses signal mit dem atmel wohl nicht erzeugen kann?...Wie exakt??
Die (analogen) Servos wollen in einem Zyklus von 20 ms (das sind die 50 Hz) ein positives Signal von 1 bis 2 ms für Anschlag eine Seite bis Anschlag andere Seite. Es gibt Aussagen, dass die Zykluszeit in einem weiten Bereich schwanken darf, vermutlich sogar mehr als 40 bis 60 Hz. Wichtig ist das Verhältnis von positivem Signal zur "Pause". Also würde ich an Deiner Stelle nicht die absolute Genauigkeit fordern - abgesehen davon, dass Du mit dem Quarz sowieso gut bestückt bist. Ich fahre Servos mit dem internen Oszillator (mit Abweichungen im Prozentbereich, je nach Temperatur) und es gibt null Probleme.
Irgendwie habe ich rausgelesen, dass Du die PWM in Software realisieren willst. Dafür also :
- mach Dir eine Interruptroutine, die in der Sekunde 50 mal aufgerufen wird.
- In dieser Routine zähle eine Variable - sagen wir mal von 1000 - abwärts.
- Zu Beginn der Zählerei schalte den Ausgang für den Servo auf high
- Wenn Du bei dem gewünschten Signalanteil irgendwo zwischen 100 und 200 bist, dann schalte den Ausgang bis 1000 auf low.
- bei 1000 setze die Variable wieder auf 0
Der Ausgang kann aber den Servo NICHT antreiben, der schafft irgendwo um die 20 mA - der Servo braucht viel mehr. Der Ausgang bringt Dir nur das Signal. Also:
RNControl_GND <--------> GND Servo
RNControl_Pinx <--------> SIG Servo
Netzteil o.ä. (+) <---------> (+) Servo
Netzteil o.ä. (-) <---------> (-) Servo
Du siehst, dass Du RNControl und Netzteil und Servo mit einem GND-Pegel fährst.
Viel Erfolg,
Mein Vorschlag wäre den Timer 1 mit einem Taktteiler von 8 bei einem 8MHz Quarz zu verwenden.
Das gibt dann eine Auflösung von 1µs pro Zählerstand - TCNT1.
Mit dem OCR1A ( 1...2ms ) kann man dann die Pulsweite einstellen mit dem OCR1B die Zykluszeit ( 20ms / 2(Kanäle) = 10ms ).
Das Ein- und Ausschalten der entsprechenden Ports wird in den OCR Interrupts erledigt. Im OCR1B Interrupt wird das TCNT Register auf 0 gesetzt um einen neuen Zyklus zu starten.
Das zu bearbeitende Servo wird in der OCR1B Routine hochgezählt und der entsprechende Ausgang eingeschaltet. Gleichzeitig wird die Impulsdauer aus dem Speicher für den zu bearbeitenden Kanal in das OCR1A geschrieben.
Die OCR1A Routine schaltet dann den entsprechenden Ausgang einfach wieder ab.
Das Ganze Spielchen kann dann durch ein paar Zeilen Code in den beiden Interruptroutinen am Laufen gehalten werden.
Eine Erweiterung auf mehr Kanäle ist durch Anpassung der Zykluszeit OCR1B und den Überlauf des Kanalzählers leicht zu erreichen.
Wenn man nicht über eine Zykuszeit von 20ms kommen will sind 8..9 Kanäle möglich. OCR1B muss immer größer sein als OCR1A !!!
Da der Zähler ja mit µs Impulsen läuft ist auch die Berechnung der Impulslängen kein Hexenwerk, ein Zählerstand von 1500 entspricht somit 1,5ms = Servomitte. Man hat also zwischen dem minimalwert 1000 und dem maximalwert von 2000 - 1000 Stufen. So genau geht kein Servo.
oberallgeier
06.01.2008, 20:05
Hallo wkrug,
Mein Vorschlag wäre den Timer 1 ... Auflösung von 1µs pro Zählerstand - TCNT1 ... 2000 - 1000 Stufen. So genau geht kein Servo.ohhh - und ich schlage mich mit einer 8bittigen PWM herum, die für meine Zwecke (fast) zu grob ist.
Folgende Initialisierung habe ich - vorzugsweise auf dem mega16 - laufen:
/* #####>>>>> Hier müssen die Motorports der RNControl umbenannt werden. Sie sind
definiert nach altem (RN/Mega32) und neuem (tiny2313) Stand:
Pin auf L293(D) RN/Mega32 tiny2313
EN1, EN2 1, 8 alt auf PD4, PD5 (OC1B,OC1A) neu: PB4, PB3
IN1, IN2 7, 2 alt auf PC6, PC7 neu: PB2, PB5
IN3, IN4 10,15 alt auf PB0, PB1 neu: PB0, PB1 << bleibt
#### */
void init_timer1(void) //Initialisierung des Timers für Erzeugung des PWM-Signals
{
/* normale 8-bit PWM aktivieren ,
Das Bit WGM10 wird im Datenblatt auch als PWM10 bezeichnet */
TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10);
/* Einstellen der PWM-Frequenz auf 14 kHz ( Prescaler = 1 ) */
TCCR1B = (1<<CS10);
/* Interrupts für Timer1 deaktivieren
Achtung : Auch die Interrupts für die anderen Timer stehen in diesem Register */
// TIMSK &= ~0x3c; //Versuche ÄHNLICHE Register zu setzten im tiny2313
/* M32: Bit 7 6 5 4 3 2 1 0
OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0 TOIE0
im M32 gesetzt 0 0 1 1 1 1 0 0 entspr. 3C
t2313 TOIE1 OCIE1A OCIE1B - ICIE1 OCIE0B TOIE0 OCIE0A
im tiny gesetzt 1 1 1 - ? ? 0 ? entspr. E0 od. ED
*/
// TIMSK &= ~0xe8; // dies gilt für tiny2313
TIMSK &= ~0x3c; // dies gilt für mega16(+32)
}
Das läuft ganz gut, mit etwa 30 µs Zyklusdauer. Aber ich kann eben nur in 254 Schritten differenzieren.
void setPWM1(uint8_t speed)
{OCR1BL = speed;}
void setPWM2(uint8_t speed)
{OCR1AL = speed;}
Wie bitte macht man das nach DEINER Methode? Hättest Du da bitte einen Vorschlag? Geht das dann auch mit dem L293D? Übrigens ist der Timer0 schon mit einer anderen Aufgabe belegt (50µs-Takt für eine Zykluszeitmessung zur Drehzahlbestimmung).
Chip type : ATmega16
Program type : Application
Clock frequency : 8,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
************************************************** ***/
#include <mega16.h>
volatile unsigned char uc_channel;
volatile unsigned int ui_pwm[4];
volatile unsigned int ui_cycle;
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
PORTC=0; // Port C abschalten = alle Ausgänge aus
}
// Timer 1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)
{
switch(uc_channel)
{
case 0:
PORTC.0=1; // Kanal 1 ein
OCR1A=ui_pwm[0];
break;
case 1:
PORTC.1=1; // Kanal 2 ein
OCR1A=ui_pwm[1];
break;
case 2:
PORTC.2=1; // Kanal 3 ein
OCR1A=ui_pwm[2];
break;
case 3:
PORTC.3=1; // Kanal 4 ein
OCR1A=ui_pwm[3];
break;
};
TCNT1=0;
uc_channel++;
if ( uc_channel>3){uc_channel=0;};
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=Out Func1=Out Func0=Out
// State7=T State6=T State5=T State4=T State3=0 State2=0 State1=0 State0=0
PORTC=0x00;
DDRC=0x0F;
// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000,000 kHz
// Mode: Normal top=FFFFh
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
TCCR1A=0x00;
TCCR1B=0x02;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x18;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
uc_channel=0;
ui_pwm[0]=1300; // Pulsbreite Kanal 1
ui_pwm[1]=1400; // Pulsbreite Kanal 2
ui_pwm[2]=1500; // Pulsbreite Kanal 3
ui_pwm[3]=1600; // Pulsbreite Kanal 4
ui_cycle=5000; // 4 Kanale, jeder 4te Zyklus bediendt wieder den selben Kanal
OCR1B=ui_cycle;
// Global enable interrupts
#asm("sei")
while (1)
{
// Place your code here
};
}
Probier den Code mal aus, sollte die Funktion so erfüllen wie ich es beschrieben hab. Also 8MHz Quarz mit 8/1 Taktteilung auf Timer 1.
Der Code ist für die Bedienung von 4 Kanälen auf PortC 0 ... 3 ausgelegt.
Die gewünschten PWM Werte sind in ui_pwm[0...3] abzulegen.
Der Überlaufwert und der Zyklenzähler ist auf die Anzahl der Kanäle einzustellen.
Ich hab den Code mal so auf die schnelle zusammengefügt - man möge mir bitte deshalb eventuelle Fehler verzeihen.
Wenn man es noch schneller haben will, kann man die Interrupt Routinen auch in Assembler schreiben.
Die Impulserzeugung läuft in Software, deshalb ist jeder beliebige Port als Ausgang verwendbar.
@oberallgeier
Mit dem L293D hab ich noch nichts gebastelt - ich kann dir also nicht sagen ob der Code auch damit geht.
radbruch
07.01.2008, 06:27
Hallo
In Anlehnung an den Servo-Code aus dem RN-Wissen steuert mein 8MHz-ATMega32 meine bis zu 5 Servos mit einem Timer im CTC-Mode mit ca. 100kHz:
...
DDRA |= 16;
DDRC |= 3;
TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR0 |= (0 << CS02) | (1 << CS01) | (0 << CS00); // prescaler /8
TIMSK = (1 << OCIE0); // Interrupt ein
OCR0 = 9; // 100kHz?
sei();
}
ISR(TIMER0_COMP_vect)
{
static uint16_t count=0;
if(count>x) PORTA &= ~16; else PORTA |= 16;
if(count>y) PORTC &= ~1; else PORTC |= 1;
if(count>z) PORTC &= ~2; else PORTC |= 2;
if(count<1000)count++; else count=0;
};
Warum meine Servos bei Werten von ca. 100 in der Mitte stehen, weiß ich nicht, ist aber nicht wirklich störend.
Wichtig ist das Verhältnis von positivem Signal zur "Pause".
Entscheidend ist die Pulslänge. Ja schneller die Wiederholung, umso "agressiver" bewegen sich die Servos.
Gruß
mic
Entscheidend ist die Pulslänge. Ja schneller die Wiederholung, umso "agressiver" bewegen sich die Servos.
Im Prinzip ist das schon richtig, aber nicht alle Servos kommen mit verkürzten Pausezeiten ( 10ms ) zurecht.
Mit Hubschrauber Heckservos für Ansteuerung mit Kreisel sollten auch Pausen von 10ms noch OK sein.
Um mit allen auf dem Markt üblichen Servos zurecht zu kommen sollte man aber trotzdem lieber bei 20ms Pausezeiten bleiben, wenn man die leicht erhöhte Reaktionszeit nicht unbedingt braucht.
JoSch1337
07.01.2008, 11:28
wow! vielen, vielen dank für den code!!
werde gleich alle drei ausprobieren und melde mich dann was jeweils passiert.
EDIT: mein board hat übrigens nen atmega32 und einen 16MHz quartz
radbruch
07.01.2008, 17:28
Hallo
Bei 16MHz müßte bei meinem Code dann folgendes geändert werden:
OCR0 = 9; würde zu OCR0 = 19;
Weniger als 10ms mögen meine 5€ler auch nicht.
Gruß
mic
mein board hat übrigens nen atmega32 und einen 16MHz quartz
Bei meinem Code musst Du dann die OCR Werte verdoppeln also 2600 anstatt 1300 und 10000 anstatt 5000 usw.
Du kriegst aber dann auch ein Auflösung von 0,5µs = 2000 Schritte
JoSch1337
09.01.2008, 15:25
@radbruch: könntest du deinen code etwas mehr komplettieren? ich weiß wenig damit anzufangen und was muss ich includen damit er sei() kennt?
@oberallgeier: eine solche timer init funktion habe ich auch in meinem code aber du übergibst ganz andere werte was an meinem 16MHz quartz liegen sollte
@wkrug: kannst du mir erklären was ui_pwm bei dir machen und wie man nun konkret den pwm setzt?
dein code compiliert bei mir nicht - es sind zig namen undeclared.
Ich weiß auch nicht warum im forum mit thema "rn-control" code für einen atmel16 mit 16MHz quartz gepostet wird - oder gibt es den rn-control auch mit diesen bauteilen?
mein aktueller code sieht so aus:
[...]
void init_timer1(void)
{
TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10)|(1<<WGM11);
TCCR1B = (1<<CS12);
TIMSK &= ~0x3c;
}
int main(void)
{
int stellung = <je nach bitwert des PWM>
DDRD |= 0xB0;
OCR1BL = stellung;
damit dreht er sich auch schon nur sehr unvorhersehbar.
was muss ich in meinem fall in TCCR1A und TCCR1B schreiben damit ich die servostellung per OCR1BL oder OCR1AL kontrollieren kann?
es wäre wirklich hilfreich einfach ein kleines funktionierendes code snippet zu haben welches ich mit avr-gcc für meinen atmel32 compiliere und testen kann! auf jeden fall vielen dank für eure hilfe aber ich bin zu sehr newbie um atmel16 code einfach mal so für meinen atmel32 umzuschreiben.
kann den code nicht jmd. auf seinem rn-control mit einem servo testen?
radbruch
09.01.2008, 16:54
Hallo
sei() und cli() sind in interrupt.h. Ich habe dir mal mein Programm auf's nötigste geputzt, ich hoffe, es funzt so:
#include <avr/io.h> // I/O Port definitions
#include <avr/interrupt.h> // Interrupt macros
uint8_t x, y, z;
void delay(uint16_t d)
{
uint16_t d1, dummy;
for (d1=d; d1>0; d1--) dummy^=d1;
}
void init(void)
{
cli();
DDRA |= 16;
DDRC |= 3;
TCCR0 = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0 |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR0 |= (0 << CS02) | (1 << CS01) | (0 << CS00); // prescaler /8
TIMSK = (1 << OCIE0); // Interrupt ein
OCR0 = 9; // 100kHz?
sei();
}
ISR(TIMER0_COMP_vect)
{
static uint16_t count=0;
if(count>x) PORTA &= ~16; else PORTA |= 16;
if(count>y) PORTC &= ~1; else PORTC |= 1;
if(count>z) PORTC &= ~2; else PORTC |= 2;
if(count<1000)count++; else count=0;
};
int main(void)
{
init();
z=105; y=110; x=90; delay(50000);
z=90; delay(10000);
while(1);
return 0;
}
Die Funktion delay() habe ich inzwischen so gelöst:
volatile uint16_t count, time;
void delay(uint16_t d) // Warteschleife
{
d+=time; while(d>time);
}
und in der ISR:
if (count < 1000) count++; else { count=0; time++; }
Gruß
mic
@JoSch1337
@wkrug: kannst du mir erklären was ui_pwm bei dir machen und wie man nun konkret den pwm setzt?
dein code compiliert bei mir nicht - es sind zig namen undeclared.
ui_pwm[0..3] sind die Impulsdauern für die Servokanäle 1...4.
Ich hab die mal einfach willkürlich auf beliebige Werte gesetzt.
Gültige Werte sollten im Bereich von 1000...2000 bzw. 1150...1950 liegen.
Das gilt für einen 8MHz Quarz und Taktteiler 8 für Timer 1.
Bei 16MHz sind die Werte 2000...4000 einzugeben und auch der Wert für uc_cycle zu verdoppeln.
Der Code ist für den C - Compiler "CodeVision AVR" gemacht ist. Mein Codevision compiliert ihn ohne Fehlermeldung.
Die Einstellwerte für die Register des Timers 1 sind auch einwandfrei auslesbar.
TCCR1A=0x00;
TCCR1B=0x02;
....
TIMSK=0x18;
In den Bemerkungen oberhalb des Abschnittes wird auch genau erklärt was da eigentlich eingestellt wird.
Die paar Zeilen Code auf AVR-GCC anzupassen sollte aber auch nicht wirklich ein Problem sein - oder?
SEI ist ein Assembler Befehl, der Global die Interrupts freigibt. Wie macht AVR - GCC das ?
Das Include File passt natürlich auch nicht, es muss natürlich das passende von AVR GCC genommen werden.
JoSch1337
09.01.2008, 17:43
radbruch, werde mich zuerst mal deinem code widmen denn ich glaube den verstehe ich jetzt.
init startet dabei einen timer der die entsprechenden register setzt die hoffentlich zu einem 50Hz signal führen.
aber wie kommt ISR(TIMER0_COMP_vect) von einem count von 0 weg wenn die variable jedesmal auf neue auf 0 gesetzt wird?
davon abgesehen soll der code wahrscheinlich folgendes machen:
durch einen timer wird fortwährend auf 1000 hochgezählt und je nachem wie x, y und z gesetzt sind die entsprechenden ports an und wieder aus geschaltet. somit wäre es anscheind möglich an jedem beliebigen port so ein pwm zu erzeugen.
wie ich nun auf die 50Hz komme ist mir ein rätsel - woher soll ich die genauen register wissen? die, die ich momentan gesetzt habe und die eine partielle fukntion ermöglichen decken sich ja überhauptnicht mit eurem code.
radbruch
09.01.2008, 18:15
Hallo
Durch das "static" wird count nur einmal mit dem Startwert geladen und behält dann seinen aktuellen Wert bei jedem Aufruf der ISR bei. (In der delay()-Variante mit time ist count global)
In init() wird der Timer mit prescale/8 im CTC-Mode gestartet, d.h. er zählt von 0 bis zum Vergleichswert (9 bei 8MHz, 19 bei 16MHz) und ruft dann die ISR auf. Das sollte 8000000/8/10=100kHz ergeben (oder 16000000/8/20). In der ISR wird dann count auf 1000 gezählt, dass ergibt 100 Herz als Wiederholung. Hier beginnt dann die "Grauzone": Bei 100KHz (1/100000) dauert ein count 0,01ms, meine Servos (verschiedene Hersteller) stehen bei ca. 100 counts, was 1 ms entspricht, in der Mitte, von ca. 50-150 machen sie 180°. Eigentlich sollte Mitte aber bei 1,5ms sein, ich habe keine Ahnung, warum das nicht passt. (Das stört mich nicht wirklich, ich würde nur gerne wissen, wo der Fehler liegt.)
Das ist aber keine echte PWM, es werden lediglich verschieden lange Impulse erzeugt. Und das mit einem "normalen" Timer und nicht mit den PWM-Modi des Timers. Vermutlich decken sich deshalb die von dir verwendeten Register nicht mit meinen.
Gruß
mic
MartinFunk
09.01.2008, 18:43
hi JoSch1337,
ich hab das so gemacht nur mit dem timer0!
http://martin.roboterbastler.de/elektronik/Servo.html
https://www.roboternetz.de/wissen/index.php/Servos#Ansteuerung
hab ich mit bis zu 16 servos bei 16 Mhz getestet dann darf der mega aber nur noch wenige andere dinge tun.
MfG Martin
JoSch1337
09.01.2008, 19:44
@martinfunk: das hört sich vielversprechend an - ich werde das nachher alles mal ausprobieren!
was ich noch nicht verstehe sind zeilen wie:
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1
OCR2 = F_CPU/100000;
diese stelle ich ja je nach quartz ein, oder? solange ich aber nur copy&past mache und nicht verstehe was ich tue bin ich jedoch immer nur auf euch angewiesen mir zu sagen wie das bei 16MHz auszusehen hat.
radbruch
09.01.2008, 20:24
Hallo Martin, hallo JoSch
Mein Code ist von diesen Beispielen abgeleitet, allerdings verwende ich prescaler /8 und dafür OCRx=9. Im Orginal mit prescaler /1 wird ins OCR-Register 80 eingetragen und damit sollen die Servos mit 100-200 laufen. Das machen meine eben nicht.
@JoSch:
Die unterschiedlichen Taktfrequenzen der Kontroller werden durch OCRx = F_CPU/100000; wieder ausgeglichen. Wenn der Takt z.B. doppelt so hoch ist, ist der es Wert für OCR auch, der Timer braucht deshalb doppelt soviel Takte um auf OCR zu zählen, weil er aber auch doppelt so schnell zählt, gleicht es sich aus. Oje, reichlich viele doppelt, ich hoffe, das ist halbwegs verständlich...
Gruß
mic
JoSch1337
14.01.2008, 12:19
Hi!!
Vielen Dank an euch alle!!
Es hat sich nun dieser code: http://martin.roboterbastler.de/elektronik/Servo.html
als optiimal herausgestellt! funzt zufriedenstellen - der servo hat brav alles gemacht was ich ihm gesat habe!
Dafür gibts jetzt ein anderes Problem - just nachdem ich das Board eine Weile nach dem Test zu weiteren Zwecken wieder anschalten wollte ging es nicht an!!! TOT!!! wie kann das sein??
Hier der Link zu einem neuen Thread den ich dafür eröffnet habe: https://www.roboternetz.de/phpBB2/viewtopic.php?t=37230
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.