OK,
dann solltest du auch so intelligent sein, und dir die Handhabung von Timern und Interrupts ansehen.
grüsse,
vohopri
Druckbare Version
OK,
dann solltest du auch so intelligent sein, und dir die Handhabung von Timern und Interrupts ansehen.
grüsse,
vohopri
...oder mal die Suchfunktion bemühen...
stimmt, ich schau mir mal des an, was in RN-Wissen steht.
Ich hab jetz mal folgenden Code ausprobiert:
der hat funktioniert, nachedm ich servopos als integer deklariert hab.Code:#define SERVOPIN 7
#define SERVOPORT PORTD
#define DDRSERVO DDRD
volatile unsigned char servopos;
void servo_init()
{
TIMSK|=(1<<OCIE2);
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1, CTC mode
OCR2 = F_CPU/100000; //alle 10µS ein IRQ
DDRSERVO|=(1<<SERVOPIN);
};
ISR(TIMER2_COMP_vect)
{
static int count;
if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
else SERVOPORT|=(1<<SERVOPIN);
if(count<2000+servopos)count++;
else count=0;
};
der folgende code für zwei servos funktioniert aber nicht so richtig:
wenn ich im Interrupt den Teil für den ersten Servo auskommentier läuft der erste, wenn ich den zweiten auskommentier läuft der zweite.Code:#define SERVOPIN_LEFT (1<<PA1)
#define SERVOPIN_RIGHT (1<<PA2)
#define SERVOPORT PORTA
#define DDRSERVO DDRA
#define LEFT_SERVO 450
#define RIGHT_SERVO 420
volatile unsigned int servopos_left;
volatile unsigned int servopos_right;
void servo_init()
{
TIMSK |= (1<<OCIE2);
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1, CTC mode
OCR2 = F_CPU/100000; //alle 10µS ein IRQ
};
ISR(TIMER2_COMP_vect)
{
static int count_left;
static int count_right;
if(count_left > servopos_left)
SERVOPORT &= ~SERVOPIN_LEFT;
else
SERVOPORT |= SERVOPIN_LEFT;
if(count_left < 2000 + servopos_left)
count_left++;
else count_left=0;
if(count_right > servopos_right)
SERVOPORT &= ~SERVOPIN_RIGHT;
else
SERVOPORT |= SERVOPIN_RIGHT;
if(count_right < 2000 + servopos_right)
count_right++;
else count_right=0;
};
Aber beide gleichzeitig laufen nicht.
Ach ja, ich hab ne main-schleife :) :
Code:int main(void)
{
DDRA = 255;
servo_init();
servopos_left = 500;
servopos_right = 370;
sei();
while(1)
{
}
while(1);
return 0;
}
Weiß irgendwer, wo der Fehler in meinem Programcode liegt?
Mach die Servo-Ansteuerung lieber über hardware-PWM an den Pins OC1a und OC2.
Lied dir dazu im Datenblatt des Controllers den Artikel "Timer/counter" (oder so ähnlich) durch, dann brauchst du nicht mal Interrupts.
Ich würde Fast-PWM empfehlen (ich finde, das kann man am schönsten einstellen.
Grüße, Yaro
ah, danke, ich werds ausprobieren
Ok, ich hab jetz mal nen Code erstell:
Code:DDRD |= (1<<PD4) | (1<<PD5);
TCCR1A |= (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0)| (1<<WGM12) | (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<CS11);
Ok, ich hab jetz mal nen Code erstell:
Jetzt weiß ich bloß nicht, wie ich OCR1A und OCR1B einstellen muss.Code:DDRD |= (1<<PD4) | (1<<PD5);
TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<COM1A0)|(1<<COM1B0)|(1<<WGM12)|(1<<WGM11)|(1<<WGM10);
TCCR1B |= (1<<CS11);
Hallo
Deine ISR von oben sollte besser so aussehen:
Mit dem "count=1" kann man mit servopos=0 den Impuls ganz ausschalten.Code:ISR(TIMER2_COMP_vect)
{
static int count;
if(count > servopos_left)
SERVOPORT &= ~SERVOPIN_LEFT;
else
SERVOPORT |= SERVOPIN_LEFT;
if(count > servopos_right)
SERVOPORT &= ~SERVOPIN_RIGHT;
else
SERVOPORT |= SERVOPIN_RIGHT;
if(count < (2000)
count++;
else
count=1;
};
Trotzdem stimmt etwas mit dem Takt nicht denn die Werte für die Servopositionen sind viel zu hoch:
Bei einem 10µs-Interrupt wären das 5ms oder 3,7ms! Und 2000 als count-Wert würden auch keine 20ms ergeben. Deshalb reicht dir auch das char für servopos nicht aus.Zitat:
servopos_left = 500;
servopos_right = 370;
Sollen wir nun das Datenblatt wälzen um das Setup des Timers zu kontrollieren? Je nach Timer-Mode und Taktfrequenz/Prescaler werden OCR1A und OCR1B eingestellt. Bei nur zwei Servos erscheint mir die Verwendung der ISR-Lösung einfacher.Code:TCCR1A |= (1<<COM1A1) | (1<<COM1B1) | (1<<COM1A0) | (1<<COM1B0)| (1<<WGM12) | (1<<WGM11) | (1<<WGM10);
TCCR1B |= (1<<CS11);
Gruß
mic