Nachtrag:
Ich hab mir mal nen ATMEGA88 beschafft und meine Idee mit den PinChanges realisiert.
Das klappt auch, wenn alle Servoimpulse zur gleichen Zeit eintreffen.
Code:
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.3 Standard
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project : Einzelimpulse zu Summensignal
Version : 1.0
Date : 30.12.2014
Author :
Company : Germany
Comments:
Chip type : ATmega88
Program type : Application
Clock frequency : 16,00000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
Zeitversatz beim Einlesen der Impulse 15µs!
*****************************************************/
/********
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")
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 braucht 630 Words, also 1260Byte
Lesezeichen