Datum:
Hallo zusammen! Ich nutze einen C167CS auf Phytec MiniModul mit dem Tasking Compiler. Mein Programm soll periodisch (alle 20 ms) Ports (3.0-3.3) in Abhängigkeit von CAN-Daten schalten. Dazu nutze ich den Timer T6. Der Code ist erprobt und sollte eigentlich funktionieren. Mein Problem ist, dass die Interrupt Routine nicht von T6 nicht ausgelöst wird und ich nicht dahinter komme, warum. Vielleicht sieht jemand einen Fehler. Ich habe schon mehrere Tage erfolglos danach gesucht. Mein Main-Programm sieht wie folgt aus:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <reg167.h> #include "can_ext.h" #include "global.h" void main (void) { /* Interrupts zulassen */ //IEN = 1; /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier erstmals bedienen */ //WDTsrv(); /* Voreinstellungen */ /* ================ */ /* CAN-Controller */ C167.CAN_fehler = FALSE; C167.CAN_rdy = FALSE; /* Taktzeitueberschreitung */ C167.zeitfehler = FALSE; /* Egofahrzeug-Daten */ //EgoFzg.v = 0; //Regler.einschalten = FALSE; /* Initialisierung der Timer, Interupts, etc. */ /* ========================================== */ /* Initialisieren des kurzen Haupttimers : Timer 3 ist ein 16bit-Timer mit einer Zeitaufloesung von 6.4 us */ // Gesamtdurchlaufzeit: 419 ms; raufzählend T3 = 0; /* Timer 3 auf Null setzen */ T3CON = 0x44; // binaer : 00 00 1 000 100; 0x44 /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier nochmals bedienen */ WDTsrv(); /* Initialisierung CAN1 und CAN2 mit 500 kBit/s */ StartCAN(0); //StartCAN(1); /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier nochmals bedienen */ WDTsrv(); /* Takt-Timer initialisieren : Timer 6 ist ein 16-bit Timer mit einer Zeitaufloesung von 3.2 us */ T6CON = 0; /* Timer 6 stoppen */ T6 = (unsigned int)6250; /* Taktzeit 20 ms */ CAPREL = (unsigned int)6250; /* Taktzeit als Reload-Wert */ T6CON = 0x80C4; /* binaer : 1 0000 00 011 000 100 */ T6IC = 0x39; // Einstellen des Interruptlevels fuer Takt-Interrupt : enable, Level 14, Gruppenlevel 1 */39 T6IE = 1; /* Interrupt enablen */ /* * Watchdog-Timer hier nochmals bedienen */ WDTsrv(); /* CAN steht zur Verfuegung */ C167.CAN_rdy = TRUE; /* * Port 3.0 schaltet Flashlights * (Output, Push/Pull, passiv) */ _putbit(1,DP3,0); _putbit(0,ODP3,0); _putbit(0,P3,0); /* * Port 3.1 schaltet Starkhorn * (Output, Push/Pull, passiv) */ _putbit(1,DP3,1); _putbit(0,ODP3,1); _putbit(0,P3,1); /* * Port 3.2 schaltet LED-Matrix Bild 1 * (Output, Push/Pull, passiv) */ _putbit(1,DP3,2); _putbit(0,ODP3,2); _putbit(0,P3,2); /* * Port 3.3 schaltet LED-Matrix Bild 2 * (Output, Push/Pull, passiv) */ _putbit(1,DP3,3); _putbit(0,ODP3,3); _putbit(0,P3,3); /* Interrupts zulassen */ IEN = 1; /* Hauptschleife */ while (1) { ; } } |
Die Interrupt-Routine, welche ausgeführt werden soll sieht so aus.
#include <stdio.h> #include <stdlib.h> #include <reg167cs.h> #include "can_ext.h" #include "global.h" interrupt 0x26 void TAKT(void) { unsigned int t6ic_alt = 0; //static int counter = 1; /* waehrend der Abarbeitung keinen neuen Interrupt zulassen */ t6ic_alt = T6IC; T6IC = 0; /* if (counter < 100) counter++; else counter = 1; */ //if(counter%2==0) { // alle 20 ms; Taktung: 10 ms (Timer 6) vRel = vEigen - vZielUebergabe; // Relativgeschwindigkeit berechenen vZiel = vEigen + vRel; // Tatsächtiche Zielgeschwindigkeit aEigen = (vEigen - vEigenVortakt) * (1000 / taktzeit); //Eigenbeschleunigung aZiel = (vZiel - vZielVortakt) * (1000 / taktzeit); // Zielbeschleunigung aRel = aZiel - aEigen; // Relativbeschleunigung aRelMax = -800 - aEigen; // Maximale Relativbeschleunigung dReferenz1 = vEigen * vEigen * 7 / 12500; // Referenzabstand für die 1. Warnstufe [cm/s] dReferenz2 = vEigen * vEigen / 2500; // Referenzabstand für die 2. Warnstufe [cm/s] radikand = vRel * vRel + aRel * abstand * 2; // Wurzelberechnung wurzel = isqrt_heron(radikand); // Wurzelberechnung tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000; // Bremszeit1; Vergleichszeit Stufe 1 tBrems2 = ((vRel * 1000 / - aRelMax) / 2) + 1600; // Bremszeit2; Vergleichszeit Stufe 2 ttcBesch = (wurzel - vRel) * 1000 / aRel; ttcConst = (abstand / vRel) * 1000; switch (sensorAus) { case 1: fehlerIDIS(); break; // IDIS hat sich abgeschaltet default : if (aRelMax >= 0) { // Das Egofahrzeug führt eine Notbremsung durch notbremsung(); }// else if (vRel < -100 && aRelMax < 0) {} // Ziel entfernt sich else if (vRel >= -100 && vRel <= 100 && aRelMax < 0) { // Ziel folgt if (abstand <= dReferenz2) stufe2(); if (abstand <= dReferenz1 && abstand > dReferenz2) stufe1(); //if (abstand > dReferenz1) allesOk(); } else { // Ziel fährt auf if (vRel * vRel >= - aRel * abstand * 2 && aRel != 0 && aRelMax < 0) { // TTC mit beschleunigten Fahrzeugen if (ttcBesch <= tBrems2 && ttcBesch > 0) stufe2(); if (ttcBesch > tBrems2 && ttcBesch <= tBrems1) stufe1(); //if (ttcBesch > tBrems1 || ttc < 0) allesOk(); } else if (aRel == 0 && aRelMax < 0) { // Keine Relativbeschleunigung --> Formel für unbeschleunigte Bewegung if (ttcConst <= tBrems2) stufe2(); if (ttcConst > tBrems2 && ttcConst <= tBrems1) stufe1(); //if (ttcConst > tBrems1) allesOk(); } } vEigenUebergabe = vEigen * 36 / 100; // Umrechnung der Einheiten und Auflösung für IDIS daten[0] = (gierrate&0x00FF); daten[1] = ((gierrate&0xFF00)>>8); daten[2] = (vEigenUebergabe&0x00FF); daten[3] = ((vEigenUebergabe&0xFF00)>>8); daten[4] = (lenkwinkel&0x00FF); daten[5] = ((lenkwinkel&0xFF00)>>8); daten[6] = (bremslicht); daten[7] = 0; def_mo_16x(0,14, 0, 0x333, 1, 8, 0, 0); ld_modata_16x(0,14, (unsigned char*)&daten); send_mo_16x(0,14); } //counter++; vZielVortakt = vZiel; vEigenVortakt = vEigen; //} T6IC = t6ic_alt; // Interrupt wieder zulassen } |
Grüße, Andreas
Datum:
Also. Ich bin mir 99% sicher, dass Du das Interrupt-Flag nicht sichern und rücksetzen musst. Das erledigt für dich entweder der µC oder der Compiler. Lösungsvorschlag zu Deinem Problem: Hast Du die Interrupts (sinnvoll) priorisiert (habe die Konfig oben nicht näher untersucht)? Sind die Timer soweit hardwareseitig aktiviert (schau mal in Deine Startup-Konfiguration) und rennt Timer6 überhaupt? Ansonsten baue Dir ein kleines Test-Projekt, in dem Du ohne viel Beeinflussung den Fehler finden kannst (mit Timer6 z.B. eine LED im Sekundenrhythmus toggeln, o.ä.).
Datum:
In der while-Schleife wird der Watchdog doch nicht bedient. Macht der die Probleme?
Datum:
sdfgq5zg schrieb: > Also. Ich bin mir 99% sicher, dass Du das Interrupt-Flag nicht sichern > und > rücksetzen musst. Das erledigt für dich entweder der µC oder der > Compiler. > > Lösungsvorschlag zu Deinem Problem: Hast Du die Interrupts (sinnvoll) > priorisiert (habe die Konfig oben nicht näher untersucht)? > Sind die Timer soweit hardwareseitig aktiviert (schau mal in Deine > Startup-Konfiguration) und rennt Timer6 überhaupt? > > Ansonsten baue Dir ein kleines Test-Projekt, in dem Du ohne viel > Beeinflussung den Fehler finden kannst (mit Timer6 z.B. eine LED > im Sekundenrhythmus toggeln, o.ä.). Danke für die schnellen Antworten! Hab jetzt mit der Prüfung einzelner Segmente angefangen. Kenntnisstand bis jetzt: Timer laufen, und zwar richtig. Überhaupt, habe ich hardwareseitig schon alles doppelt und dreifach geprüft. Ich glaub, dass was übersehe... Guido schrieb: > In der while-Schleife wird der Watchdog doch nicht bedient. > Macht der die Probleme? Watchdog ist es nicht. Habe ihn schon mal stillgelegt, ohne Ergebnis. Außerdem ist er auf 419 ms eingestellt, deshalb denke ich nicht, dass er hier Probleme macht. Aber danke für den Tipp! Grüße, Andreas
Datum:
Ist das beim Tasking-Compiler wirklich so:
interrupt 0x26
void TAKT(void)
{
}
und nicht so wie beim Keil µVision:
void TAKT(void) interrupt 0x26
{
}
?
Datum:
Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0 Sinn. Du solltest das IR Flag zurücksetzen in der Interruptroutine, sonst nichts.
Datum:
Andreas schrieb: > T6IC = 0x39; // Einstellen des Interruptlevels fuer Takt-Interrupt : enable, Level 14, Gruppenlevel 1 */39 > T6IE = 1; /* Interrupt enablen */ ersetze die beiden Anweisungen gegen
T6IC = 0x79;
|
ach ja, in der ISR kannst du den Interrupt mit dem T6IE ein- und ausplanen.
Datum:
sdfgq5zg schrieb: > Ist das beim Tasking-Compiler wirklich so: Ja, es ist so. Anders spuckt der Compiler einen Fehler aus. Steel schrieb: > Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0 > Sinn. Du solltest das IR Flag zurücksetzen in der Interruptroutine, > sonst nichts. Ok, mach ich. Obwohl ich vermute, dass das nicht der Grund für mein Leiden ist... Pipeline schrieb: > ersetze die beiden Anweisungen gegenT6IC = 0x79; Das habe ich der Übersichtlichkeitshalber gemacht. So kann ich den Timer stilllegen, ohne jedes mal binär in hex umzurechnen. Pipeline schrieb: > ach ja, in der ISR kannst du den Interrupt mit dem T6IE ein- und > ausplanen. Wie oben angemerkt, werde ich es gleich mal versuchen...
Datum:
> Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0 > Sinn. Richtig! Der Interrupt unterbricht sich nicht selbst! Alle Interrupts mit gleichem oder niedrigerem Level unterbrechen diesen Interrupt nicht. Das IR Bit wird automatisch vom Prozessor zurückgesetzt. In Deinem hier gezeigtem Code wird der Watchdog tatsächlich nicht bedient, allerdings gehört ja noch weiterer Code dazu, in dem der Watchdog wahrscheinlich bedient wird? Zum Testen würde ich den Watchdog definitiv erst mal ausschalten. Wo werden denn die Port 3 Pins geschaltet und wie sieht der Code dazu aus?
Datum:
So, anscheinend habe ich (zumindest) eine Stelle lokalisieren können. Anscheinend geht der Interrupt. Da ich die Bedungungen durch Variablen festlegen kann, habe ich eine speziellen Fall erzeugt, und zwar: Ziel folgt mit abstand <= dReferenz2. Bei der Berechnung von dReferenz2 stockt er. Das Problem liegt bei "vEigen * vEigen". Das kriegt er irgendwie nicht gebacken. Ersetze ich vEigen durch den Wert, z.B. 2400 - läuft es. Es funktioniert auch, wenn ich eine Zwischenvariable deklariere und mit der weiter rechne. Also nochmal zusammengefasst:
vEigen = 2400; dReferenz1 = vEigen*vEigen/2500; // geht NICHT! dReferenz1 = 2400*2400/2500; // geht! vEigen = 2400; bla = vEigen * vEigen; dReferenz1 = bla/2500; // geht! |
Ich verstehe überhaupt nicht, wie das kommt! In meinen Augen ist das unlogisch!
Datum:
Als was sind die Variablen deklariert? Integer? Passt das Ergebnis nicht in ein Integer gibt es Probleme...
Datum:
B. Jue schrieb: > Als was sind die Variablen deklariert? Integer? > Passt das Ergebnis nicht in ein Integer gibt es Probleme... Ja, sind alle Integer. Für die Berechnung sollte das ja reichen. Was mich wundert, ist das es mit einer Zwischenvariablen funktioniert...
Datum:
B. Jue schrieb: > Als was sind die Variablen deklariert? Integer? > Passt das Ergebnis nicht in ein Integer gibt es Probleme... War doch die Deklaration! Einige Variablen sind überlaufen. Vielen Dank für den Hinweis. Ich hoffe, das jetzt Ruhe ist! =)
Datum:
Andreas H. schrieb: > Ja, sind alle Integer. Für die Berechnung sollte das ja reichen. Andreas H. schrieb: > vEigen = 2400; > dReferenz1 = vEigen*vEigen/2500; Frage: Wieviel sind 2400*2400? Antwort: ;-) Andreas H. schrieb: > Anscheinend geht der Interrupt. Wie debugst du eigentlich?
Datum:
Pipeline schrieb: > Frage: Wieviel sind 2400*2400? > Antwort: ;-) Jaja=), unter Windows/Linux ist int meist ausreichend. Natürlich ist es bei einem 16-Bit uC anders... Hab ja schon vermutet, dass ich irgendwo gut auf dem Schlauch gestanden habe. Pipeline schrieb: > Wie debugst du eigentlich? Das Debuggen ist recht abenteuerlich. Entweder spreche ich Ports an, oder schick mir über CAN was. Richtiges Debuggen geht nicht, weil ich den Tasking nur im Rahmen des Minimodul-Pakets nutzen kann. Das bedeutet compiliren --> flashen --> gucken.
Datum:
Wenn ich zwei 16-Bit-Integers multipliziere und in eine 16-Bit-Integervariable ablege, dürfte ich gar keine Probleme mit dem Überlauf haben. Das Resultat mag nicht das sein, was man erwartet (obere 16Bit abgeschnitten), das wird aber keinen Interrupt verhindern.
Datum:
sdfgq5zg schrieb: > das wird aber keinen Interrupt verhindern. Hat es auch nicht. Der OT hat es nur nicht gemerkt.
Datum:
Habe gerade festgestellt, dass temporären Variablen auch alle int sind. Wie Caste ich die denn richtig?
tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000; |
Hier liegt das Problem in "vRel*1000", wobei vRel auch 1000 gesetzt ist. Als Antwort bekomme ich da ungefähr 16000 raus. Casten mit (long)(vRel*1000) funktioniert nicht... Weiß jemand Rat?
Datum:
Andreas H. schrieb: > Casten mit > (long)(vRel*1000) funktioniert nicht... kann auch nicht, da du mit 16Bit rechnest und das übergelaufende Ergbnis auf 32Bit erweiterst. Du möchtest aber mit 32Bit rechnen. Andreas H. schrieb: > tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000; mal ungeprüft aus der hohlen Hand:
tBrems1 = (((long)vRel * (long)1000 / - aRelMax) / 2) + 1600 + 2000; |
wobei ein cast genügen würde.
Datum:
Nachschlag: casting show schrieb: > wobei ein cast genügen würde schaust Du hier: http://de.wikibooks.org/wiki/C%2B%2B-Programmierun...