hallo, ich programmiere mit dem Mikrocontroller at90can128 und versuche CAN_Felher zu behandeln. Ich möchte eine Meldung bekommen, wenn ich z.B die CAN-Kabel ziehe. Ich habe die folgende Funktion implementiert #define CAN_BUS_OFF 0x00 #define CAN_PASSIVE 0x01 #define CAN_SUCCESS 0x02 int8_t AtCanGetBusState(void) { if (CANGSTA & (1<<BOFF)) return CAN_BUS_OFF; if (CANGSTA & (1<<ERRP)) return CAN_PASSIVE; return CAN_SUCCESS; } jetzt bekomme ich die Meldung nach dem ich die Kabel wieder eingesteckt habe. Gibt es eine Möglichkeit diese Funktion in beliebige Zeit aufzurufen und nicht in eine bestimmte Stelle im main aufzurufen. Ich meine beim Laufen des Programms wird plötzlich die Kabel gezogen und in der Zeitpunkt bekomme ich die passende Rückgabe Wert. Auf alle Hilfe bin ich sehr dankbar
Ich glaube, dass einfach Bus-Kabel ziehen an sich von einem CAN-Controller noch nicht als Fehler empfunden wird. Das Problem kommt, wenn der Controller ein Meldung sendet und - weil das Kabel gezogen ist - niemand am Bus antwortet. Vorschlag: miss die Zeit, zu der Meldungen zum Senden abgelegt werden (z.B. in einer Tabelle mit 15 Eintraegen, einem pro MOb) und, in Deiner Warteschleife, schau nach ob eine MOb "zu lange" schon eine gesendet werdende Meldung hat. Wenn ja, dann hast Du Deinen Fehler, und Du kannst diese Meldung loeschen. "Zu lange" laesst sich aus der Bitrate und Reserven fuer Behandlung im Sender und Empfaenger abschaetzen. Ich verwende zu diesem Zweck das obere Bit des CAN Timers (CANTIMH), mein Timer laeuft mit 10 kBps (Bus Takt = 100kBps). Hier ist die Prozedur CanCheckWait, die ich in meiner Warteschleife periodisch aufrufe (wenn nichts zu tun ist, alle 10 msec - jedes Mal wird eine neue MOb geprueft)- meine Tabelle ist in can_status.cs_stamp (uint8_t):
1 | // Check next MOB for send-hang
|
2 | // ----------------------------
|
3 | // Consider an MOB as hanging if xmit is not terminated after > 75 msec
|
4 | //
|
5 | // Return the MOB ordinal if the MOB hangs
|
6 | // Return -1 if the MOB is OK
|
7 | |
8 | int8_t CanCheckWait () |
9 | {
|
10 | uint8_t x_mob ; // ordinal of MOB to check |
11 | int8_t x_wait ; |
12 | |
13 | static uint8_t next_mob = 0 ; // next MOB to check |
14 | |
15 | // Determine which MOB to check
|
16 | // - the variable next_mob does a circular walk-trough { 0 .. 14 }
|
17 | // - do nothing if the MOB is not transmitting
|
18 | |
19 | if ( next_mob > 14 ) next_mob = 0 ; // circular overflow modulo 14 |
20 | x_mob = next_mob++ ; |
21 | CANPAGE = x_mob << 4 ; |
22 | if ( ( CANCDMOB & _BV(CONMOB0) ) == 0 ) return -1 ; // OK if not sending |
23 | |
24 | // Check the time spent since the launch of the transmission:
|
25 | // - cs_stamp is the value of CANTIMH at transmission launch,
|
26 | // - the high byte of the CAN-timer (CANTIMH) has increments of
|
27 | // 25.6 msec (at 10kHz = 0.1 msec increments of CANTIML),
|
28 | // - sampling jitter = 25.6 msec due to only considering CANTIMH.
|
29 | //
|
30 | // x_wait > 3 ... frame hold detection at 76.8 ... 102.4 mseconds
|
31 | |
32 | x_wait = CANTIMH - can_status.cs_stamp[x_mob] ; |
33 | if ( x_wait < 0 ) x_wait += 256 ; // handle counter wrap-around |
34 | if ( x_wait > 3 ) return x_mob ; |
35 | return -1 ; |
36 | }
|
hallo Juergen, ich versuche deine Code zu verstehen und auch bei mir zu implementieren und melde ich mich wieder. Ich danke Dir
hallo juergen, habe ich das Datenblatt über Timer/Counter gelesen, weil ich zum ersten mal damit beschäftige. In deiner code sehe ich nicht wo Du die Register für Timer/Counter gesetzt hat. Wie wählst Du das Timer? Im Datenblatt steht dass CANTIML bzw CANTIML nur Leseregister sind.Du sagst, dass Du obere Bit des CAN Timers (CANTIMH) verwendest. Außerdem verstehe ich diese Zeile: x_wait = CANTIMH - can_status.cs_stamp[x_mob] ; Bitte kannst Du mir noch einmal mehr Eklärungen geben. Wie muss ich zuesrt das Timer setzen? Ich danke Dir
Also wenn der Controller sendet und kein ACK bekommt, geht der erstmal von ACTIVE nach ERROR_PASSIVE. Das kann man sich auch mit einem IRQ in einer Variablen signalisieren lassen und dann per Vergleicher in der Mainloop, eine Änderung detektieren. Dann sollte man in jedem Fall mitbekommen, wenn man vom CAN "abgekoppelt wird". Das schöne ist, dass wenn man das Kabel wierder einsteckt, nach einer gewissen Anzahl fehlerfreier Nachrichten, der Zustand automatisch wider in den ACTIVE geht.
Da habe ich es mir vielleicht etwas leicht gemacht: ich hatte verstanden, das der Zustand von ACTIVE nach ERROR_PASSIVE kippt, wenn es zufolge IRGENDEINES Fehlers 127mal schief geht, und das als "zu kompliziert" links liegen lassen - mein Hauptproblem war, nach haengengebliebenen MObs zu fischen. Muss ich mir genauer anschaun. Zur urspruenglich gestellten Frage: zum Erkennen des Fehlers ist das einfacher - aber was geschieht mit dem MOb das der Kontroller nicht los wird? - Deine Wahl. Antwort zu den spezifischen Fragen. Geh zum Artikel in http://www.mikrocontroller.net/articles/CAN_Bibiliothek_f%C3%BCr_AT90CAN_Prozessoren und hole Dir in den Links am Ende die Dateien Can.c und Can.h. Suche darin nach can_status.cs_stamp - das zeigt Dir wie diese Variable gehandhabt wird ( und wie sie beim Senden eines Frames gesetzt wird). In CanInit siehst Du wie CANTCON initialisiert wird - das bestimmt den Takt fuer CANTIM, CANTIMH und CANTIML laufen dadurch "von selber". Die Zeile mit xmit_wait: sie rechnet die abgelaufene Zeit seit dem Senden aus. In can_status.cs_wait liegt der Zeitpunkt (CANTIMH Einheiten) beim Senden, das wird mit dem momentanen Wert von CANTIMH verglichen (ueberlauf-behandelt) und ergibt "wie alt" der Sendeprozess ist - und can_status.cs_stamp ist eine Tabelle, indiziert mit dem MOb Index.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.