Hallo

Das funktioniert nur, wenn du in der RP6BaseLib.c die Timer2-Overflow-ISR komplett ersetzt:
https://www.roboternetz.de/phpBB2/vi...=318456#318456

Inzwischen, das ist ja schon zwei Jahre her, erkenne ich auch, dass diese Art der Ansteuerung ziemlicher Mist ist. Deshalb rate ich von der Benutzung eher ab.

Da die RP6-Library alle Timer verwendet, muss man bei der Servoansteuerung immer Kompromisse eingehen, die von der jeweiligen Anwendung abhängig sind:

Das einfachste (wie oben schon beschrieben) ist eine blockierende Ansteuerung (mit Sleep() oder Zählschleife) bei der das Programm wartet, bis das Servo seine Position erreicht hat. Das ist für erste Servoversuche die übersichtlichste Lösung. Diesen Ansatz mit einem Servo an SCL hatte ich hier mal in das Tasksystem eingebunden:
Code:
#include "RP6RobotBaseLib.h"

#define pos1 800
#define pos2 1600

extern uint8_t acs_state;

uint16_t servo_pos, servo_timer, servo_dummy;

int main(void) {

	initRobotBase();
	DDRC |= 1;
	
	startStopwatch1();
	startStopwatch2();
	servo_pos = pos1;
	
	while (1)
	{
		if ((getStopwatch1() > 20) && (acs_state < 2)) // alle 20ms einen Servoimpuls erzeugen
		{
	      setStopwatch1(0);
			servo_timer = servo_pos;
	      PORTC|=1;
			while(servo_timer--) servo_dummy ^= servo_timer;
	      PORTC&=~1;
		}

		if (getStopwatch2() > 1000) // alle 1000ms Servo auf andere Seite fahren
		{
			if (servo_pos == pos1) servo_pos=pos2; else servo_pos=pos1;
			setStopwatch2(0);
		}
      //task_RP6System();
      task_ADC();
		task_ACS();
		task_Bumpers();
      task_motionControl();
	}
return 0;
}
Alle Servoansteuerungen, die im Hintergrund ausgeführt werden, müssen einen Timer umbiegen und blockieren damit die Lib-Funktion des betreffenden Timers. Ohne Timer0 gibt es keine StopWatch() und andere Zeitfunktionen mehr, ohne Timer1 funktionieren die Motoren nicht mehr und ohne Timer2 gibt es keine 36kHz-Trägerfrequenz fürs IR. Das bedeutet, man muss sich entscheiden, auf welche Funktionsgruppe man verzichten möchte und steuert die Servos dann mit dem freien Timer an. Dabei kann man natürlich jederzeit wieder die orginale Funktion des Timers aktivieren indem man initRobotBase() aufruft und das Timersetup der Lib wiederherstellt. Hier eine resourcenschonende Variante mit Timer2 und drei Servos an SDA, SCL und E-INT am XBUS:
Code:
//Servos mit Timer2 Overflow-ISR                                 27.2.2008 mic

#include "RP6RobotBaseLib.h"

uint8_t pos[3]={255,170,85}; // Positionen der drei Servos an SDA, SCL und E_INT

int main(void)
{
	initRobotBase();
	DDRA |= 16;
	PORTA &= ~16;
	DDRC |= 3;
	PORTC &= ~3;

	//Timer2 Initialisierung
	TCCR2 = (0 << WGM21) | (0 << COM20) | (1 << CS22); // Normal Mode, prescaler /64
	TIMSK |= (1 << TOIE2); // Timer2 Overflow-Interrupt erlauben

	while(1)
	{
	   pos[0]=pos[1]=pos[2]=170;
	   mSleep(1000);
	   pos[0]=pos[1]=pos[2]=220;
	   mSleep(1000);
	   pos[0]=pos[1]=pos[2]=170;
	   mSleep(1000);
	   pos[0]=pos[1]=pos[2]=120;
	   mSleep(1000);
	}
	return(0);
}
ISR (TIMER2_OVF_vect)
{
	static uint8_t servo_nr=0;
	static uint16_t impulspause;
	if(servo_nr)
	{
	   if(servo_nr==1) {TCNT2=-pos[0]; PORTC |= 1; impulspause-=pos[0];}
	   if(servo_nr==2) {TCNT2=-pos[1]; PORTC &= ~1; PORTC |= 2; impulspause-=pos[1];}
	   if(servo_nr==3) {TCNT2=-pos[2]; PORTC &= ~2; PORTA |= 16; impulspause-=pos[2];}
	   if(servo_nr==4) {PORTA &= ~16; servo_nr=0;}
	   if(servo_nr) servo_nr++;
	}
	else
	{
	   if(impulspause>256) impulspause-=256;
			else {TCNT2=-impulspause; servo_nr++; impulspause=1500;}
	}
}
In diesem Zusammenhang möchte ich noch den ADC-Interrupt erwähnen. Er wird von der RP6-Lib nicht verwendet und eignet sich auch dazu, Servoimpulse im Hintergrund zu erzeugen. Der ADC läuft dabei im Dauerlauf, dadurch wird allerdings der Zugriff auf unterschiedliche ADC-Kanäle etwas komlizierter. Ein Beispiel mit Servos an den LEDs und SDA/SCL:
Code:
// Domino Day für den RP6 mit neuem Greifarm und ADC-ISR         19.1.2008  mic

#include "RP6RobotBaseLib.h"

uint16_t s1, s2, s3, s4 ,s5, s6;

void servo_ON(void)
{
	cli();
// Freeruning, 5V-Ref, ISR enable, prescale /32 ((8MHZ/32)/12,5 sind ca. 20kHz bzw. 0,05us)
// AVCC with external capacitor at AREF pin, Ergebniss linksbündig, Kanal ADC7 (UBAT)
	ADMUX = (0<<REFS1) | (1<<REFS0)  | (1<<ADLAR) | 7;
// setzte free running triggern
	SFIOR = (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
// Interrupt ein, Wandler einschalten, prescaller /32
	ADCSRA = (1<<ADIE) | (1<<ADEN) | (1<<ADPS2) | (0<<ADPS1)  | (1<<ADPS0);
// Autotriggern bedeutet jetzt free running aktivieren, altes Flag löschen
	ADCSRA |= (1<<ADATE) | (1<<ADIF);
// Initialisierung starten
	ADCSRA |= (1<<ADSC);
// und noch die wohl eher unnötige Initiallesung
	while (!(ADCSRA & (1<<ADIF)));
	ADCSRA |= (1<<ADIF);

	DDRC |= 0x70;		// LED1-3 auf Ausgang und low
	PORTC &= ~0x70;
	DDRB |= 0x83;		// LED4-6 auf Ausgang und low
	PORTB &= ~0x83;
	DDRC |= 0x3;		// SCL und SDA auf Ausgang und low
	PORTC &= ~0x3;
	sei();
}
void servo_OFF(void)
{
	cli();
	// Initialize ADC: (Defaultsetup der RP6-Library)
	ADMUX = 0; //external reference
	ADCSRA = (0<<ADIE) | (0<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADIF);
	SFIOR = 0;
	sei();
	setLEDs(0); // LEDs restaurieren
}
int main(void)
{
	initRobotBase();

	s1=25;
	s2=25;
	s3=25;
	s4=25;
	s5=25;
	s6=25;
	servo_ON();
	setLEDs(63);
	mSleep(2000);
	setLEDs(0);
	while(1)
	{
		mSleep(1000);
		s1=40;
		mSleep(1000);
		s1=25;
		mSleep(1000);
		s2=35;
		mSleep(1000);
		s2=15;
	}
	return 0;
}

ISR(ADC_vect)
{
	static uint16_t count=0;
	(count>s1)?(PORTC&=~SL1):(PORTC|=SL1);
	(count>s2)?(PORTC&=~SL2):(PORTC|=SL2);
	(count>s3)?(PORTC&=~SL3):(PORTC|=SL3);
	(count>s4)?(PORTB&=~SL4):(PORTB|=SL4);
	(count>s5)?(PORTB&=~SL5):(PORTB|=SL5);
	(count>s6)?(PORTB&=~SL6):(PORTB|=SL6);

	(count>s1)?(PORTC&=~1):(PORTC|=1); // SCL
	(count>s2)?(PORTC&=~2):(PORTC|=2); // SDA

	(count<500)?count++:(count=0);
}
Bitte beachtet, dass ich inzwischen ziemlich viel Zeit mit Servoansteuerungen vergeudet habe...

Gruß

mic