Also ich würde den Ansatz mit dem Lehrer / Schüler system weiterverfolgen.
Von ACT gibt es ein drahtloses Lehrer / Schüler system. http://www.acteurope.de/html/t3e-leh...er-system.html
Die Pulsfolge ist 9 Impulse mit 500µs Länge, gefolgt von der gewünschten Servoimpulslänge - 500µs als Pause.
Also soll der impuls 1500µs ( = Servomitte ) betragen muss die Pause 1000µs sein.
Die 9 Impulse ( bei 8 zu übertragenden Kanälen ) deshalb weil bei einem Hersteller die steigenden Flanken im Lehrer Sender ausgewertet werden, bei einem anderen die fallenden.
Nach einen solchen Impulskette kommt eine 6ms lange Pause, damit der Lehrer Sender weiss, wann der erste Kanal wieder anfängt.
Die Anschlussbelegung deiner Fernsteuerung sollte sich rauskriegen lassen.
Ich hab so ein System mit nem ATMEGA 88 gebaut und es funktioniert problemlos.
Code:
/********
PC0 = Kanal 1
PC1 = Kanal 3
PC2 = Kanal 5
PC3 = Kanal 7
PD0 = Kanal 2
PD1 = Kanal 4
PD2 = Kanal 6
PD3 = Kanal 8
PB1 = Summensignalausgang
PB2 = Syncsignal startet bei Pausenbeginn
********/
#include <mega88.h>
volatile unsigned int ui_timerold[8]; //Speicherwerte für die Steigende Flanke der entsprecheden Kanäle
volatile unsigned int ui_pulslengh[8]={3000,3000,3000,3000,3000,3000,3000,3000}; //Ermittelte Pulslängen
volatile unsigned int ui_lastchange; //Letzter Impulsstart für Summensignalgenerierung
volatile unsigned char uc_oldgerade=0; //Zwischenspeicher für den alten Zustand der geraden Kanäle 2,4,6,8
volatile unsigned char uc_oldungerade=0; //Zwischenspeicher für den alten Zustand der geraden Kanäle 1,3,5,7
volatile unsigned char uc_cyclecount; //Zyklenzähler für die Impulsausgabe
#define maxcycle 17 //Maximale Zyklenzahl für die Impulsausgabe
#define minlengh 1200 //Minimal zulässige Impulslänge 600µs
#define midlengh 3000 //Servo Mittelstellung
#define maxlengh 5400 //Maximal zulässige Impulslänge 2700µs
#define interpulspause 1000 //1000 = 500µs
#define interframepause 12000 //12000 = 6ms Interframepause
//#define normal //Bestimmt ob die Impulsausgabe normal oder invers geschehen soll
//#define revers //zur Zeit noch nicht implementiert - Bedingte Assemblierung
#define portsungerade PINC //Ungerade Kanäle auf Port C
#define portsgerade PIND //Gerade Kanäle auf Port D
#define outport PORTB.1 //Summen Ausgangssignal
#define syncport PORTB.2 //Sync Signal für Oszilloskop
// Pin change 8-14 interrupt service routine Kanal 1,3,5,7
interrupt [PCINT1] void pin_change_isr1(void)
{
unsigned char uc_portungerade,uc_result,uc_low,uc_high;
unsigned int ui_timer;
uc_portungerade=portsungerade;
uc_low=TCNT1L;
uc_high=TCNT1H;
ui_timer=uc_high;
ui_timer=ui_timer<<8;
ui_timer+=uc_low;
uc_portungerade&=0x0F;
uc_result=uc_portungerade^uc_oldungerade;
if(uc_result&0x01)
{
if(uc_portungerade&0x01) //Es war ne steigende Flanke
{
ui_timerold[0]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[0]=ui_timer-ui_timerold[0];
};
}
if(uc_result&0x02)
{
if(uc_portungerade&0x02) //Es war ne steigende Flanke
{
ui_timerold[2]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[2]=ui_timer-ui_timerold[2];
};
}
if(uc_result&0x04)
{
if(uc_portungerade&0x04) //Es war ne steigende Flanke
{
ui_timerold[4]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[4]=ui_timer-ui_timerold[4];
};
}
if(uc_result&0x08)
{
if(uc_portungerade&0x08) //Es war ne steigende Flanke
{
ui_timerold[6]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[6]=ui_timer-ui_timerold[6];
};
}
uc_oldungerade=uc_portungerade;
}
// Pin change 16-23 interrupt service routine Kanal 2,4,6,8
interrupt [PCINT2] void pin_change_isr2(void)
{
unsigned char uc_portgerade,uc_result,uc_low,uc_high;
unsigned int ui_timer;
uc_portgerade=portsgerade;
uc_low=TCNT1L;
uc_high=TCNT1H;
ui_timer=uc_high;
ui_timer=ui_timer<<8;
ui_timer+=uc_low;
uc_portgerade&=0x0F;
uc_result=uc_portgerade^uc_oldgerade;
if(uc_result&0x01)
{
if(uc_portgerade&0x01) //Es war ne steigende Flanke
{
ui_timerold[1]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[1]=ui_timer-ui_timerold[1];
};
}
if(uc_result&0x02)
{
if(uc_portgerade&0x02) //Es war ne steigende Flanke
{
ui_timerold[3]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[3]=ui_timer-ui_timerold[3];
};
}
if(uc_result&0x04)
{
if(uc_portgerade&0x04) //Es war ne steigende Flanke
{
ui_timerold[5]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[5]=ui_timer-ui_timerold[5];
};
}
if(uc_result&0x08)
{
if(uc_portgerade&0x08) //Es war ne steigende Flanke
{
ui_timerold[7]=ui_timer;
}
else //Es war ne fallende Flanke
{
ui_pulslengh[7]=ui_timer-ui_timerold[7];
};
}
uc_oldgerade=uc_portgerade;
}
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
unsigned char uc_low,uc_high;
unsigned int ui_buffer;
switch(uc_cyclecount)
{
case 0: //Die Pausen
syncport=0; //Sychronosationsimpuls stoppen
outport=1;
uc_low=OCR1AL;
uc_high=OCR1AH;
ui_buffer=uc_high; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+uc_low;
ui_lastchange=ui_buffer;
ui_buffer+=interpulspause; //Preimpuls dazuzählen und einfügen
uc_low=ui_buffer&0x00FF;
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 1:
outport=0; //Der erste Impuls
ui_buffer=ui_lastchange+ui_pulslengh[0];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 2: //Pausen zwischen den Impulsen einfügen
case 4:
case 6:
case 8:
case 10:
case 12:
case 14:
case 16:
outport=1;
uc_low=OCR1AL;
uc_high=OCR1AH;
ui_buffer=uc_high; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+uc_low;
ui_lastchange=ui_buffer;
ui_buffer+=interpulspause; //Pause zwischen den Impulsen dazuzählen und einfügen
uc_low=ui_buffer&0x00FF;
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 3:
outport=0; //Der zweite Impuls
ui_buffer=ui_lastchange+ui_pulslengh[1];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 5:
outport=0; //Der dritte Impuls
ui_buffer=ui_lastchange+ui_pulslengh[2];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 7:
outport=0; //Der vierte Impuls
ui_buffer=ui_lastchange+ui_pulslengh[3];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 9:
outport=0; //Der fünfte Impuls
ui_buffer=ui_lastchange+ui_pulslengh[4];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 11:
outport=0; //Der sechste Impuls
ui_buffer=ui_lastchange+ui_pulslengh[5];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 13:
outport=0; //Der siebte Impuls
ui_buffer=ui_lastchange+ui_pulslengh[6];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 15:
outport=0; //Der achte Impuls
ui_buffer=ui_lastchange+ui_pulslengh[7];
uc_low=ui_buffer&0x00FF; //OCR Register für nächsten Interrupt vorbelegen
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 17:
syncport=1; //Syncpuls Starten
outport=0;
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=interframepause; //Pause zwischen den Frames also nach 8 Impulsen einfügen
uc_low=ui_buffer&0x00FF;
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
}
uc_cyclecount++;
if(uc_cyclecount>maxcycle){uc_cyclecount=0;}
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
unsigned char uc_i;
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T
PORTB=0x00;
DDRB=0x06;
// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=P State2=P State1=P State0=P
PORTC=0x0F;
DDRC=0x00;
// 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=P State2=P State1=P State0=P
PORTD=0x0F;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=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: Off
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
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: On
// Interrupt on any change on pins PCINT16-23: On
EICRA=0x00;
EIMSK=0x00;
PCICR=0x06;
PCMSK1=0x0F;
PCMSK2=0x0F;
PCIFR=0x06;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x02;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
while(PINC.0==0); //Warten auf Impulse
while(PINC.0>0);
// Watchdog Timer initialization
// Watchdog Timer Prescaler: OSC/128k
// Watchdog Timer interrupt: Off
#pragma optsize-
#asm("wdr")
WDTCSR=0x1E;
WDTCSR=0x0E;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Global enable interrupts
#asm("sei")
while (1)
{
#asm("wdr")
//Fehlerhafte Impulse abfangen
for (uc_i=0;uc_i<8;uc_i++)
{
if(ui_pulslengh[uc_i]<minlengh||ui_pulslengh[uc_i]>maxlengh)
{
ui_pulslengh[uc_i]=midlengh;
}
};
};
}
Der Code ist für Codevision AVR, sollte sich aber problemlos portieren lassen.
Im Prinzip brauchst Du da jetzt nur noch die Kinect an den Controller anpassen und die entsprechenden Kanäle ansprechen und es sollte laufen.
Lesezeichen