C-Programm auf XC866 'verzählt' sich
Hallo zusammen,
ich habe in etwas komplexeres Problem.
Ich möchte einem Microcontroller vom Typ Infineon XC866 von einem Rechner mit W2k über eine 8-Bit-Verbindung insgesamt 5 Byte übermitteln. Dazu hat der Rechner eine GPIB-Interfacekarte. Vor dem Controller hängt das Gegenstück zu dieser Karte. Sprich, wenn ich im Programm auf dem Rechner sage, ich möchte das 2. Bit im 5.Byte der GPIB-Nachricht setzen wird eine bestimmte Leitung an der Karte vor dem Controller auf high gezogen.
So habe ich also meine 8 Bitleitungen von der Karte an den Controller verdrahtet. Eine 9. Leitung benutze ich, um dem Controller mit einer steigenden Flanke zu singalisieren, dass jetzt 8 Bit anliegen und er diese bitte 'abholen' soll. Auf die steigende Flanke reagiere ich mit einem Interrupt.
Im folgenden also meine Interrupt Service Routine (ISR) für die 9. Leitung:
Code:
void TriggerISR() interrupt 8
{
IRCON0 &= 0xfb; //reset IR-Bit of trigger
switch (counter)
{
case 0:
time1 = P3_DATA; //get LSB of time
if (time1 == 0)
{
P0_DATA &= 0xf8;
P0_DATA |= 1;
}
else
{
if (time1 == 1)
{
P0_DATA &= 0xf8;
P0_DATA |= 2;
}
}
break;
case 1:
time2 = P3_DATA; //get 2nd byte of time
if (time2 == 0)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x3;
}
else
{
if (time2 == 1)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x4;
}
}
break;
case 2:
time3 = P3_DATA; //get MSB of time
if (time3 == 0)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x1;
}
else
{
if (time3 == 13)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x7;
}
}
break;
case 3:
phase = P3_DATA; //get phase information
if (phase == 0)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x6;
}
else
{
if (phase == 128)
{
P0_DATA &= 0xf8;
P0_DATA |= 0x1;
}
}
break;
case 4:
switch (P3_DATA)
{
case 0:
usePhase = 0; //-> phase ignored
mainc = 0; //use serial contactors
break;
case 1:
usePhase = 1; //-> phase important
mainc = 0; //use serial contactors
break;
case 2:
usePhase = 0; //-> phase ignored
mainc = 1; //use main contactor
break;
case 3:
usePhase = 1; //-> phase important
mainc = 1; //use main contactor
break;
}
break;
}
counter++;
}
Dabei stellt P3_DATA meine 8 Eingänge dar, an denen die Bytes empfangen werden sollen. An P0.0 bis P0.2 hängen drei high-aktive Dioden, die ich angebracht habe, damit ich mir anzeigen lassen kann, an welcher Stelle im Programm ich bin (debuggen geht leider nicht!).
Und nun mein Problem:
Wenn ich eine Byte-Kombination übergebe, die in den if-else-Blöcken abgefangen wird funktioniert alles wunderbar. Wenn ich dagegen eine Kombination übergebe, die nicht in den ersten if-else-Block reingeht springt er mir anscheinend über den zweiten break drüber (Vermutung!) und macht auch gleich noch den case 2 mit.
Anschaulich heißt das:
1. Byte = 1
2. Byte = 0
3. Byte = 13
4. Byte = 0
5. Byte = 2
--> alles passt!
1. Byte = 2
alle anderen Bytes sind egal, er macht mir, sobald ich das zweite Byte übermittle (z.B. ne 0) zuerst ganz kurz die Dioden für die 3 an, anschließend sofort die Diode für die 1!
1. Byte = 1
2. Byte = 2
3. Byte = 13
4. Byte = 0
5. Byte = 2
--> alles passt!!!
Ich hoffe mal, ihr versteht was ich meine. Wenn nicht fragt bitte nach, dann versuche ich es auf eine andere Art zu erklären.
Was ich schon alles versucht habe:
1. In den verschiedenen cases jeweils den counter auf die nächste Zahl zu setzen (statt counter++ am Ende)
2. In den if-else-Blöcken eine else im if, mit einem return (damit er auch sicher aus der Funktion aussteigt)
3. einen anderen Interrupt zu nehmen
4. den switch durch 5-if-Abfragen zu ersetzen
5. die if-else-Blöcke durch switch mit default-Zweig zu ersetzen
Hat leider alles nichts gebracht!
Wieso reagiert das Programm falsch, wenn der erste Wert nicht im if-else-Block abgefangen wird???
Ich hoffe mal, ihr könnt mir helfen, bin echt schon am verzweifeln!
Danke fürs lesen und viele Grüße
Jetzt wirds richtig toll....
Guten Morgen,
danke für die schnelle Antwort! Bin gestern nur nicht mehr dazu gekommen noch weiter zu basteln.
Hier also meine Erkenntnisse von heute:
Ich habe die ganzen if-else-Abfragen auskommentiert, das IR-Bit erst am Ende der ISR rückgesetzt und den Counter an P0 ausgegeben. Und jetzt wirds richtig mysteriös:
Wenn ich eine Kombination übergebe, die VORHER im if-else des 1. Bytes abgefangen wurde geht alles gut, er zählt ganz normal bis 5 hoch und ich bin glücklich.
Wenn ich eine Kombination übergebe, die nicht im if-else des 1. Bytes enthalten war (s. Anfangsthread), dann zählt er 1 - 2 und sofort 3 - 4 - 5 - 6!
Ich habe also ein Oszilloskop drangehängt und mir mal angeschaut, was auf der Interruptleitung passiert. Fazit: Egal, was ich für Werte übergebe, es schaut immer gleich aus (okay, mit gewissen Toleranzen, die von der 'Echtzeitfähigkeit' von Windows kommen)! Sprich, es wird definitiv nur ein Interrupt ausgelöst!!!
Hab auch bei beiden switches einen default: break eingefügt, hat auch nix gebracht.
Hast du vielleicht noch Ideen??? Hast ja geschrieben fürs erste :-)
Im folgenden nochmal mein Code (in der neuen Fassung):
Code:
void TriggerISR() interrupt 8
{
P0_DATA &= 0xf8;
switch (counter)
{
case 0:
time1 = P3_DATA; //get LSB of time
break;
case 1:
time2 = P3_DATA; //get 2nd byte of time
break;
case 2:
time3 = P3_DATA; //get MSB of time
if (time3 == 0)
break;
case 3:
phase = P3_DATA; //get phase information
break;
case 4:
switch (P3_DATA)
{
case 0:
usePhase = 0; //-> phase ignored
mainc = 0; //use serial contactors
break;
case 1:
usePhase = 1; //-> phase important
mainc = 0; //use serial contactors
break;
case 2:
usePhase = 0; //-> phase ignored
mainc = 1; //use main contactor
break;
case 3:
usePhase = 1; //-> phase important
mainc = 1; //use main contactor
break;
default:
break;
}
break;
default:
break;
}
counter++;
P0_DATA = counter;
IRCON0 &= 0xfb; //reset IR-Bit of trigger
}
Fehler liegt bei dem Interrupt
Hallo Robert,
ich habe es zwar etwas anders angestellt als du, aber ich bin mir mittlerweile definitiv sicher, dass ein 2. Interrupt ausgelöst wird, wenn ich die 'falschen' Werte übergebe.
Ich habe das ganze herausgefunden, indem ich in der ISR nacheinander in jeden case ein EA = 0 (verbietet global ALLE Interrupts) eingefügt habe. Wenn ich den in case 1 reinschreibe und Werte übergebe geht zunächst die erste LED an (für case 0), dann die 2. und dann is Ruhe. Wenn ich die Zeile in case 2 reinschreibe 'verzählt' er sich wieder. Das heißt doch, dass definitiv ein zweiter Interrupt ausgelöst wird, oder?
Dann ist nur noch die Frage woher...
Ich würde dir ja gerne ein Bild von meinem Oszilloskop schicken, aber leider kann man hier ja keine Anhänge an den Thread hängen und auf ftp-Server darf ich von hier scheinbar nicht. Also muss ich dir halt so versichern, dass es nur insgesamt 5 steigende Flanken am Eingang des Controllers gibt. Und die 3. kommt ganz sicher erst nachdem er bereits den counter auf 3 erhöht hat.
Das mit dem Disassembly wird vermutlich relativ schwierig, weil das wieder nur über Screenshot gehen wird, befürchte ich. Da hab ich aber auch schonmal reingeschaut und finde da ehrlich gesagt keinen Fehler. In einer Simulation (ohne Hardware) funktioniert das Programm auch einwandfrei.
Im Anschluß nochmal ein Originallisting meines aktuellen Programms:
Datei main.c:
Code:
//declaration of functions
extern void PortInit(void); //declared in ports.c
extern void InterruptInit(void); //declared in int.c
//declaration of variables
volatile unsigned char counter; //counter variable for number of trigger events
volatile unsigned char time1, time2, time3; //time in ms (LSB to MSB)
volatile unsigned char phase; //phase information
volatile bit usePhase; //0 if phase is not used, 1 if phase is used
volatile bit mainc; //1 if main contactor is used, else 0
void main (void)
{
PortInit(); //initialize the ports
InterruptInit(); //initialize the trigger-interrupts
counter = 0; //set starting value for counter
EA = 1; //enable all interrupts globaly
while(counter < 5); //wait for 5 transmissions from the computer
/*if (mainc == 1)
{
P0_DATA &= 0xf8; //close the serial contactors (shoot is performed with main contactor)
}*/
while(1);
}
Datei ports.c:
Code:
void PortInit(void)
{
P0_DIR = 0xb; //P0.0, P0.1 and P0.3 are outputs
P1_DIR = 0x0; //P1.1 is an input
P3_DIR = 0x0; //P3.0 to P3.7 are inputs
//for testing:
P1_DIR |= 0xc0; //P1.6 and P1.7 are outputs
P0_DIR |= 0x4; //P0.2 is an output
}
Datei int.c:
Code:
extern volatile unsigned char counter; //declared in main.c
extern volatile unsigned char time1, time2, time3, phase; //declared in main.c
extern volatile bit usePhase; //declared in main.c
extern volatile bit mainc; //declared in main.c
void InterruptInit(void)
{
//set priorities of interrupts (shoot = 2, trigger and phase = 1)
IP1 = 0x8; //reset bit for shoot, set bit for trigger
IPH1 = 0x4; //set bit for shoot, reset bit for trigger
IP |= 0x4; //set bit for phase
IPH = 0x3b; //reset bit for phase
EXICON0 = 0x14; //edge selection for the three signals
IEN0 &= 0xfb; //disable interrupt for phase (individually)
IEN1 |= 0x4; //enable interrupt for the shoot(individually)
IEN1 |= 0x8; //enable interrupt for trigger (individually)
}
void TriggerISR() interrupt 8
{
P0_DATA &= 0xf8;
switch (counter)
{
case 0:
time1 = P3_DATA; //get LSB of time
/*if (time1 == 0)
{
P0_DATA |= 1;
}
else
{
if (time1 == 2)
{
P0_DATA |= 2;
}
}*/
break;
case 1:
time2 = P3_DATA; //get 2nd byte of time
/*if (time2 == 0)
{
P0_DATA |= 0x3;
}
else
{
if (time2 == 1)
{
P0_DATA |= 0x4;
}
}*/
break;
case 2:
time3 = P3_DATA; //get MSB of time
EA = 0; //disable all interrupts
/*if (time3 == 0)
{
P0_DATA |= 0x1;
}
else
{
if (time3 == 13)
{
P0_DATA |= 0x7;
}
}*/
break;
case 3:
phase = P3_DATA; //get phase information
/*if (phase == 0)
{
P0_DATA |= 0x6;
}
else
{
if (phase == 128)
{
P0_DATA |= 0x1;
}
}*/
break;
case 4:
switch (P3_DATA)
{
case 0:
usePhase = 0; //-> phase ignored
mainc = 0; //use serial contactors
break;
case 1:
usePhase = 1; //-> phase important
mainc = 0; //use serial contactors
break;
case 2:
usePhase = 0; //-> phase ignored
mainc = 1; //use main contactor
break;
case 3:
usePhase = 1; //-> phase important
mainc = 1; //use main contactor
break;
default:
break;
}
break;
default:
break;
}
counter++;
P0_DATA = counter;
IRCON0 &= 0xfb; //reset IR-Bit of trigger
}
Wie gesagt, das EA=0 in int.c deaktiviert nur alle Interrupts (war zum Testen).
Vielen Dank für deine Bemühung!!! und viele Grüße