Ok, Ich bin dann mal so frech und hau nen Code raus.
Im Simulator hab ich das mal getestet - Da scheints zu funktionieren.
Mit nem Controller kann ich leider nicht testen ( Kein ATMEGA 88 hier ).
Ich hab das Prinzip mit dem Pinchange umgesetzt.
Die Simulation war mit 8MHz, dabei kann ein Versatz ( Jitter ) von 30µS bei den Signalen entstehen.
Code:
/*****************************************************
Project : Einzelimpulse zu Summensignal
Version : 0.1
Date : 19.12.2014
Author :
Company :
Comments:
Chip type : ATmega88
Program type : Application
Clock frequency : 8,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
Zeitversatz beim Einlesen der Impulse 30µ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
********/
#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]={1500,1500,1500,1500,1500,1500,1500,1500}; //Ermittelte Pulslängen
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 15
#define interpulspause 50 //50 = 50µs
#define interframepause 4000 //4000 = 4ms Interframepause
//#define normal //Bestimmt ob die Impulsausgabe normal oder invers geschehen soll
//#define revers
#define portsungerade PINC
#define portsgerade PIND
#define outport PORTB.1
// Pin change 8-14 interrupt service routine
interrupt [PCINT1] void pin_change_isr1(void)
{
unsigned char uc_portungerade,uc_result;
unsigned int ui_timer;
ui_timer=TCNT1H;
ui_timer=(ui_timer<<8)+TCNT1L;
uc_portungerade=portsungerade&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
interrupt [PCINT2] void pin_change_isr2(void)
{
unsigned char uc_portgerade,uc_result;
unsigned int ui_timer;
ui_timer=TCNT1H;
ui_timer=(ui_timer<<8)+TCNT1L;
uc_portgerade=portsgerade&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:
outport=1; //Der erste Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[0]; //Pulslänge dazuzählen
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 1: //Die Pausen
case 3:
case 5:
case 7:
case 9:
case 11:
case 13:
outport=0;
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=interpulspause;
uc_low=ui_buffer&0x00FF;
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
case 2:
outport=1; //Der zweite Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[1]; //Pulslänge dazuzählen
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 4:
outport=1; //Der dritte Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[2]; //Pulslänge dazuzählen
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 6:
outport=1; //Der vierte Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[3]; //Pulslänge dazuzählen
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 8:
outport=1; //Der fünfte Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[4]; //Pulslänge dazuzählen
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 10:
outport=1; //Der sechste Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[5]; //Pulslänge dazuzählen
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 12:
outport=1; //Der siebte Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[6]; //Pulslänge dazuzählen
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 14:
outport=1; //Der achte Impuls
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=ui_pulslengh[7]; //Pulslänge dazuzählen
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;
ui_buffer=OCR1AH; //Aktuelle Werte holen
ui_buffer=(ui_buffer<<8)+OCR1AL;
ui_buffer+=interframepause;
uc_low=ui_buffer&0x00FF;
uc_high=(ui_buffer>>8)&0x00FF;
OCR1AH=uc_high;
OCR1AL=uc_low;
break;
default:
uc_cyclecount=0;
}
uc_cyclecount++;
if(uc_cyclecount>maxcycle){uc_cyclecount=0;}
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
// 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=In Func1=Out Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=0 State0=T
PORTB=0x00;
DDRB=0x02;
// 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;
// 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")
// Place your code here
};
}
Auch wenn mehrere Ports ihre Level zu gleichen Zeit ändern, sollte der Code funzen.
Lesezeichen