Hallo zusammen, ich beschäftige mich derzeit mit Can. Ich verwende den ATmega64M1. Mein aktueller Stand ist, dass ich eine Nachricht verschicken kann und mit einem anderen µC greife ich die Nachricht ab und verarbeite diese weiter. Um verschiedene Nachrichten verarbeiten zu können schicke ich zweimal die Nachricht 0x55 und zweimal 0xCC. Das CAN-Signal dazu sieht auch super aus. Siehe dazu Bild1. Ich möchte, dass mit jeweils einer Nachricht eine zugewiesene LED leuchtet (if- und else if-Schleife). Ist keine Nachricht vorhanden soll auch eine LED leuchten(else-Schleife). Hier habe ich beobachtet, dass entweder die LED, welcher die Nachricht 0x55 zugeordnet ist, oder die LED welche in der else-Schleife steht, leuchtet. Starte ich das Programm, leuchtet entweder die eine oder die andere. Läuft das Programm wechselt die LED nicht. So wird anscheinend nur einmal die Nachricht abgefragt und das wars. Welche LED leuchtet ist meiner Meinung nach abhängig vom Zeitpunkt des Programmstarts. Die LED, welcher Nachricht 0xCC zugeordnet ist (else-if), leuchtet jedoch nie. Die Nachricht 0xCC wird scheinbar gar nicht vom µC erkannt! Hier ist noch wichtig zu erwähnen, dass beide Nachrichten dieselbe ID haben. Ich tausche lediglich den Inhalt der Nachricht aus. Empfangsseitig lasse ich jedoch auch alle ID’s passieren. Daher ist es wohl doch nicht so wichtig… Meine Fragen: 1.) Warum wird die Nachricht 0xCC nicht erkannt? 2.) Wird die Nachricht nur einmal zu Beginn gelesen, und wenn ja warum aktualisiert er nicht? 3.) Warum leuchtet die LED der else-Schleife? Es ist doch immer eine Nachricht da! 4.) Sind meine oben erläuterten Erkenntnisse richtig? Anbei findet Ihr das Skript zum Empfangen der Nachricht(en). Über Hilfe wäre ich sehr dankbar, da ich im Moment mit meinem Kenntnisstand nicht mehr weiter weiß. Grüße, Luk
Ich denke du wirst keine Antwort bekommen da sich niemand mit Restverstand ein docx-Dokument von hier runter lädt. Solltest du trotzdem Antworten bekommen werden die dich nicht befriedigen. Lies dir deine Fragen nochmal durch und stell dir selbst die Frage was du von dem Kauderwelsch verstehen würdest wenn dir einer solche Fragen stellen würde...
Yup, mach mal Test-Code mit dem Problem und stell den ein, ich benutze die ATMega16M1 schon etwas länger.
Hallo Rudolph, danke für die schnelle Antwort. Hier mein Code: // Header-Dateien aufrufen für Befehle #include "avr/io.h" // Globale Header-Datei für In-Output-Belegung #include "avr/interrupt.h" // Globale Header-Datei für Interrupt // Intitialsieren von Variablen (Deklarieren mach ich im main() weils in Simulation hier nicht funktionierte) int8_t i; int8_t data; // UNTERPROGRAMME DEKLARIEREN void init_variabs(void); void init_pin(void); void init_can_generell(void); //UNTERPROGRAMME ######################################################################## ######################################################################## ######################################################################## # // ######################################################################## ######################################################################## ######################################################################## # // Startwert für Variablen festlegen void init_variabs(void) { i = 0; } // Pinbelegung festlegen void init_pin(void) { // Pin PB2 zur LED-Ansteuerung DDRB = 0b00000100; // Pin B2 also Ausgang, Rest-Pins also Input, da nicht benötigt. PORTB = 0b11111011; // Pin B2 ausschalten. Rest-Pins eingeschalten, da diese als Input deklariert sind, wurde jetzt Pull-Up-Resistor aktiviert. DDRD = 0b10000000; PORTD = 0b01111111; DDRC = 0b00010000; PORTC = 0b11101111; } // Generelle Einstellungen für CAN um Daten zu senden void init_can_generell(void) { CANGCON = (1<<SWRES); // Can-Controller mit Hardware Reseted. CANGSTA = (1<<ENFG); // Enable CAN-Controller for (i=0; i<6; i++) // alle MOb's zurücksetzen. { CANPAGE = (i<<4); // select MOb-Number, um 4 shiften, da MOBNB0 das 5. Bit ist. CANCDMOB = 0x00; // disable MOb, transmission and reception CANSTMOB = 0x00; // clear status CANIDT1 = 0x00; // clear ID CANIDT2 = 0x00; CANIDT3 = 0x00; CANIDT4 = 0x00; CANIDM1 = 0x00; // clear mask CANIDM2 = 0x00; CANIDM3 = 0x00; CANIDM4 = 0x00; CANMSG = 0x00; // Daten zurücksetzen } CANBT1 = 0x0E; // Baudrate mit 250 KBaud bei fCLKio = 16MHz festgelegt CANBT2 = 0x04; // ... CANBT3 = 0x13; // ... /*CANTCON = 0x00; // CAN-Timer mit 0 geprescaled*/ CANGCON = (1<<ENASTB); // // CAN-Channel wechselt in enable mode wenn 11 recessive Bits gelesen wurden CANPAGE = (1<<MOBNB0) ; // MOb1 ausgewählt. Dies ist etwas unübersichtlich, siehe hierzu Erklärung in Doku unter Probleme. CANIDM1 = 0x00; // Alle ID's passieren lassen CANIDM2 = 0x00; CANIDM4 = (1<<IDEMSK); // Muss nicht gesetzt werden, ´wird aber unter 16.5.2.3 RX Data and Remote Frame aufgeführt CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message CANGIE = (1<<ENIT) | (1<<ENRX); // enable receive interrupt CANIE1 = 0x00; CANIE2 = (1<<IEMOB1); // enable ISR wenn MOB1 beschrieben wird CANSIT1 = 0x00; // Wenn mehrere MOb's interrupt auslösen sollen CANSIT2 = 0x00; //... } //HAUPTPROGRAMM ######################################################################## ######################################################################## ######################################################################## ## // ######################################################################## ######################################################################## ######################################################################## ## int main(void) { init_variabs(); init_pin(); init_can_generell(); sei(); //Erlaube Globale Interrupts while(1) {/* PROGRAMMSCHLEIFE*/ } return(0); } ISR(CAN_INT_vect) { data = CANMSG ; /*PORTB = 0b11111111;*/ // ROTE LED (PB2) leuchtet, Orangene LED (PC4) aus, Blaue LED (PD7) aus. if (data == 0x55) { DDRD = 0b00000000; // Alle=Eingang PORTD = 0b00000000; // Alle=Aus DDRC = 0b00000000; // Alle=Eingang PORTC = 0b00000000; // Alle=Aus DDRB = 0b00000100; // PB2=Ausgang, Rest=Eingang PORTB = 0b11111111; // PB2=High, Rest=PullUp } // BLAUE LED (PD7) leuchtet, Orangene LED (PC4) aus, Rote LED (PB2) aus. else if (data == 0xCC) { DDRB = 0b00000000; // Alle=Eingang PORTB = 0b00000000; // Alle=Aus DDRC = 0b00000000; // Alle=Eingang PORTC = 0b00000000; // Alle=Aus DDRD = 0b10000000; // PD7=Ausgang, Rest=Eingang PORTD = 0b11111111; // PD7=High, Rest= PullUp } // ORANGENE LED (PC4) leuchtet, Rote LED (PB2) aus, Blaue LED (PD7) aus. else { DDRD = 0b00000000; // Alle=Eingang PORTD = 0b00000000; // Alle=Aus DDRB = 0b00000000; // Alle=Eingang PORTB = 0b00000000; // Alle=Aus DDRC = 0b00010000; // PC4=Ausgang, Rest=Eingang PORTC = 0b11111111; // PC4=High, Rest=PullUp } for (i=0; i<6; i++) // alle MOb's zurücksetzen. { CANPAGE = (i<<4); // select MOb-Number, um 4 shiften, da MOBNB0 das 5. Bit ist. CANCDMOB = 0x00; // disable MOb, transmission and reception CANSTMOB = 0x00; // clear status CANIDT1 = 0x00; // clear ID CANIDT2 = 0x00; CANIDT3 = 0x00; CANIDT4 = 0x00; CANIDM1 = 0x00; // clear mask CANIDM2 = 0x00; CANIDM3 = 0x00; CANIDM4 = 0x00; } CANSTMOB =(0<<RXOK); // RXOK zurücksetzen // CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message } // PROGRAMMENDE ######################################################################## ######################################################################## ######################################################################## ## // ######################################################################## ######################################################################## ######################################################################## ##
Probier das mal:
1 | #include "avr/io.h" // Globale Header-Datei für In-Output-Belegung |
2 | #include "avr/interrupt.h" // Globale Header-Datei für Interrupt |
3 | |
4 | |
5 | void init_pin(void) |
6 | { |
7 | // Pin PB2 zur LED-Ansteuerung |
8 | DDRB = 0b00000100; // Pin B2 also Ausgang, Rest-Pins also Input, da nicht benötigt. |
9 | PORTB = 0b11111011; // Pin B2 ausschalten. Rest-Pins eingeschalten, da diese als Input deklariert sind, wurde jetzt Pull-Up-Resistor aktiviert. |
10 | |
11 | DDRD = 0b10000000; |
12 | PORTD = 0b01111111; |
13 | |
14 | DDRC = 0b00010000; |
15 | PORTC = 0b11101111; |
16 | } |
17 | |
18 | |
19 | void init_can_generell(void) |
20 | { |
21 | uint8_t i,j; |
22 | |
23 | CANGCON = (1<<SWRES); // Can-Controller mit Hardware Reseted. |
24 | //CANGSTA = (1<<ENFG); // Enable CAN-Controller - nope, das zeigt an, dass an ist |
25 | |
26 | for (i=0; i<6; i++) // alle MOb's zurücksetzen. |
27 | { |
28 | CANPAGE = (i<<4); // select MOb-Number |
29 | CANCDMOB = 0x00; // disable MOb, transmission and reception |
30 | CANSTMOB = 0x00; // clear status |
31 | CANIDT1 = 0x00; // clear ID |
32 | CANIDT2 = 0x00; |
33 | CANIDT3 = 0x00; |
34 | CANIDT4 = 0x00; |
35 | CANIDM1 = 0x00; // clear mask |
36 | CANIDM2 = 0x00; |
37 | CANIDM3 = 0x00; |
38 | CANIDM4 = 0x00; |
39 | for(j=0; j<8; j++) |
40 | { |
41 | CANMSG = 0x00; // Daten zurücksetzen |
42 | } |
43 | } |
44 | |
45 | CANBT1 = 0x0E; // Baudrate mit 250 KBaud bei fCLKio = 16MHz festgelegt |
46 | CANBT2 = 0x04; // ... |
47 | CANBT3 = 0x13; // ... |
48 | |
49 | CANGCON = (1<<ENASTB); // CAN-Channel wechselt in enable mode wenn 11 recessive Bits gelesen wurden |
50 | |
51 | CANPAGE = (1<<4) ; // MOb1 auswählen |
52 | CANIDM1 = 0x00; // Alle ID's passieren lassen |
53 | CANIDM2 = 0x00; |
54 | CANIDM4 = (1<<IDEMSK); |
55 | CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message |
56 | |
57 | CANGIE = (1<<ENIT) | (1<<ENRX); // enable receive interrupt |
58 | CANIE1 = 0x00; |
59 | CANIE2 = (1<<IEMOB1); // enable ISR wenn MOB1 beschrieben wird |
60 | CANSIT1 = 0x00; |
61 | CANSIT2 = 0x00; |
62 | } |
63 | |
64 | |
65 | int main(void) |
66 | { |
67 | cli(); |
68 | init_pin(); |
69 | init_can_generell(); |
70 | sei(); |
71 | |
72 | while(1) |
73 | { |
74 | |
75 | } |
76 | } |
77 | |
78 | |
79 | ISR(CAN_INT_vect) |
80 | { |
81 | uint8_t canpage; |
82 | uint8_t data; |
83 | |
84 | canpage = CANPAGE; // save canpage |
85 | |
86 | if(CANSIT2 & (1<<SIT1)) // MOB1 hat ausgelöst |
87 | { |
88 | CANPAGE = (1<<4); // select MOB1 |
89 | CANSTMOB &= ~(1<<RXOK); // clear interrupt flag |
90 | |
91 | data = CANMSG ; |
92 | |
93 | // ROTE LED (PB2) leuchtet, Orangene LED (PC4) aus, Blaue LED (PD7) aus. |
94 | if (data == 0x55) |
95 | { |
96 | PORTB |= (1<<PB2); |
97 | PORTC &= ~(1<<PC4); |
98 | PORTD &= ~(1<<PD7); |
99 | } |
100 | |
101 | // BLAUE LED (PD7) leuchtet, Orangene LED (PC4) aus, Rote LED (PB2) aus. |
102 | else if (data == 0xCC) |
103 | { |
104 | PORTB &= ~(1<<PB2); |
105 | PORTC &= ~(1<<PC4); |
106 | PORTD |= (1<<PD7); |
107 | } |
108 | |
109 | // ORANGENE LED (PC4) leuchtet, Rote LED (PB2) aus, Blaue LED (PD7) aus. |
110 | else |
111 | { |
112 | PORTB &= ~(1<<PB2); |
113 | PORTC |= (1<<PC4); |
114 | PORTD &= ~(1<<PD7); |
115 | } |
116 | |
117 | CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message |
118 | } |
119 | |
120 | CANPAGE = canpage; // restore canpage |
121 | } |
Auf das erste Byte jeder Botschaft zu reagieren ist schon etwas seltsam. Ebenso wie das deklarieren globaler Variablen die nur lokal verwendet werden. Oder das nicht so toll lesbare Bit-Gekröse in "ini_pin". In Teilen ("//set to receive, 1-byte in message") sieht das aus wie mein Beispiel-Code für den 90CAN und 16M1 der hier irgendwo rum hängt, warum hast Du dann nicht auch gleich noch den Rest benutzt? :-)
Hallo Rudolph, recht herzlichen Dank. Es funktioniert sehr gut! Ja, ich habe deinen Code als Orientierung genommen. Allerdings wollte ich es selbst probieren und nicht gleich kopieren. Aus Fehlern lernt man doch am besten. Natürlich habe ich nochmal Fragen. Du meintest "Auf das erste Byte jeder Botschaft zu reagieren ist schon etwas seltsam." 1.) Wo habe ich diese Einstellung getroffen? Indem ich nicht explizit darauf reagiere wenn MOb1 ausgelöst hat? 2.) Beim zurücksetzen der MOBs hast du for(j=0; j<8; j++) { CANMSG = 0x00; // Daten zurücksetzen } geschrieben. Du gehst da die 8 Byte des MOb durch, also setzt Byte für Byte, richtig? Wie ist j mit den einzelnen Byte verknüpft? Also woher weiß der µC, dass er von einem Byte zum nächsten gehen soll? Ansonsten kann ich deinen Code gut nachvollziehen. Spontan würde mich noch interessieren wie ich mehrere MOb's anwähle. Z.B.: CANPAGE = (1<<4); // select MOB1 CANPAGE &= (1<<4) | (1<<5); // select MOB3 Ist jetzt MOb1 und MOb3 angewählt!? Ich frage, da ich am Ende des Tages drei Sensoren via Can Daten senden lassen möchte. Jeder Sensor soll seinen eigenes MOb erhalten. Der Empfangende µC soll mit den "selben" MOb's arbeiten. Also Sensor(i) = MOb(i) --> Empfänger hinterlegt Nachricht in MOb(i). Hoffe das war verständlich. Grüße, Lukas
Lukas D. schrieb: > "Auf das erste Byte jeder Botschaft zu reagieren ist schon etwas > seltsam." > > 1.) Wo habe ich diese Einstellung getroffen? Du gibst doch in die CAN-Init für die Message-Box keine ID vor und stellst das Filter auf alle Botschaften durchlassen. Im Interrupt wird nicht auf die Botschafts-ID geprüft und das erste Byte genommen, ergo das erste Byte irgendeiner Botschaft wird benutzt. Lukas D. schrieb: > Wie ist j mit den einzelnen Byte verknüpft? Also woher weiß der µC, dass > er von einem Byte zum nächsten gehen soll? Das CANMSG Register besteht eigentlich aus acht Registern hintereinander weg, welches Byte man davon erwischt wird mit dem CANPAGE Register eingestellt - siehe Seite 245. Das ist INDX0...INDX2. Bei jedem Zugriff wird der Index automatisch hochgezählt was sich mit dem AINC Bit verhindern lassen würde. Drei Byte würde man so auslesen: data1 = CANMSG; data2 = CANMSG; data3 = CANMSG; Mit "CANPAGE = (1<<4);" wird also nicht nur das Message-Objekt ausgewählt, sondern auch noch der Index zurück gesetzt. Die CAN-Unit ist etwas beknackt, so aus AVR Sicht, die stammt wohl aus irgend einem 8051 und wurde übernommen, statt neu geschnitzt. Lukas D. schrieb: > Spontan würde mich noch interessieren wie ich mehrere MOb's anwähle. > Z.B.: > > CANPAGE = (1<<4); // select MOB1 > CANPAGE &= (1<<4) | (1<<5); // select MOB3 > > Ist jetzt MOb1 und MOb3 angewählt!? Nein, das geht nicht, man kann immer nur eine Message-Box auswählen. Man kommt ja immer nur an den Register-Satz für die jeweils ausgewählt Message-Box, das spart schlicht eine Menge Adressen im Register-Satz und die Message-Boxen sind ja bis auf die Priorität erstmal alle gleich. Das (x<<4) ist auch nur die ganz faule Schreibweise mit dem Wissen, dass die Nummer in den oberen Bits steckt. CANPAGE = 0; // select Mob0 CANPAGE = (1<<MOBNB0); // select Mob1 CANPAGE = (1<<MOBNB1); // select Mob2 CANPAGE = (1<<MOBNB1)|(1<<MOBN0); // select Mob3 Das wäre zwar sauber, das ist mir aber zu doof. :-) CANPAGE = 0x00; // Mob0 CANPAGE = 0x10; // Mob1 CANPAGE = 0x20; // Mob2 CANPAGE = 0x30; // Mob3 Das wäre vielleicht noch ein einfachere Variante. Über das CANSIT2 Register kann man feststellen welche Message-Box den Interrupt ausgelöst hat. Und wenn man auf mehreren Message-Boxen senden will muss man entsprechend jedesmal das CANPAGE Register verstellen.
Danke für die ausführliche Antwort! Ich bau die Senoren auf und versuch das mal! Deine Tipps sind auf jeden Fall sehr hilfreich! Grüße Lukas
Lukas D. schrieb: > Ich frage, da ich am Ende des Tages drei Sensoren via Can Daten senden > lassen möchte. Jeder Sensor soll seinen eigenes MOb erhalten. Der > Empfangende µC soll mit den "selben" MOb's arbeiten. Also Sensor(i) = > MOb(i) --> Empfänger hinterlegt Nachricht in MOb(i). > Hoffe das war verständlich. Den Absatz habe ich wohl zu schnell überflogen. Die Message-Boxen machen doch die Botschaft nicht aus, das ist nur der Briefkasten. Die Message-ID bestimmt was damit passiert. Ob Du 0x100 aus Mob2 oder Mob1 verschickst macht keinen Unterschied, das ist auf der anderen Seite nicht feststellbar. Aber 0x100 von zwei Sensoren zu verschicken würde zu einem Bus-Fehler führen, jede ID darf nur von jeweils einem Knoten gesendet werden. Du könntest am Empfänger eine Message-Box so konfigurieren das zum Beispiel die Botschaften mit den IDs 0x100 bis 0x107 empfangen werden. Dafür sind die Filter-Bits eigentlich da. Im Interrupt muss man dann noch feststellen welche ID konkret empfangen wurde. Die Sensoren könnte man jetzt so bauen, dass drei Pins am Controller dazu benutzt um die Sensor-Nummer zu konfigurieren. Das geht ganz gut mit den internen Pullup-Widerständen und aussen bestückten oder eben nicht bestückten 0R0 Widerständen gegen GND. Pins einlesen, das ganze noch invertieren. Jetzt wird die Sende-ID des Sensors eingestellt als 0x100+Sensor-Nummer. Und schwupp hat man acht Sensoren mit identischer Software. :-) Die empfangende Message-Box wird natürlich blockiert solange die Botschaft nicht verarbeitet wurde, aber bei einem Temperatur-Sensor zum Beispiel wäre es ja nicht so tragisch gelegentlich mal eine Botschaft zu verlieren wenn der ansonsten alle 100ms oder so seine Daten schickt.
Hallo Rudolph, ich stelle fest, dass das Datenblatt nur die nötigsten Einstellungen beinhaltet. Hast du vielleicht Links oder PDF's oder ähnliches welche mir weiter helfen können? Rudolph R. schrieb: > Du könntest am Empfänger eine Message-Box so konfigurieren das zum > Beispiel die Botschaften mit den IDs 0x100 bis 0x107 empfangen werden. Die Idee ist gut! Ich hab auch einen ähnlichen Ansatz aber immer noch ein Problem. Ich würde pro Sensor eine ID Tag vergeben. MOb2 erhält eine entsprechende IDMask um nur Nachrichten von Sensor2 aufnehmen zu können. Das heißst aber, dass ich alle 3 MOb's (für drei Sensoren) zu Beginn anwählen und konfigurieren muss um die Nachrichten in die jeweiligen Briefkästen stecken zu können! Sonst steck ich ja die Nachrichten nur in MOb1 und weiß ja nicht mehr von welchem Sensor diese ist. Rudolph schrieb: > Nein, das geht nicht, man kann immer nur eine Message-Box auswählen. Wie mach ich das dann? Ich hab noch nicht ganz verstanden wie und wann ich die MOb's anwähle. Was wäre der Trigger um z.B. MOb2 anzuwählen? Kann ich nicht vorne Weg die MOb's anwählen und einstellen? So würde ich doch dann wissen wo welche Nachricht hin muss und wo diese herkommt. Im Fortlauf hätte ich dann in der ISR drei if-Schleifen, so wie deine: Rudolph R. schrieb: > if(CANSIT2 & (1<<SIT1)) // MOB1 hat ausgelöst Ich geh dann immer in die jenige wo gerade eine neue Nachricht ankommt und kann weiterwursteln. Hier noch einmal eine Hilfestellung wäre super! Beste Grüße, Lukas
Habe noch eine Ergänzung: Die IDTag legt fest welche Nachricht zuerst gelesen werden soll. Über IDTag lege ich die Priorität fest aber auch zugleich die Adresse von wem die Nachricht empfangen werden soll. Dazu habe ich ja empfangsseitig die IDMask. Diese beiden Informationen sind im MOb hinterlegt. So gelangt die Nachricht in das MOb oder wird von diesem abgelehnt. Richtig? Also spreche ich mit IDTag und IDMask direkt ein MOb an. Dann weiß ich aber nicht wann ich wie die MOb's anwählen und konfigurieren muss.
Lukas D. schrieb: > ich stelle fest, dass das Datenblatt nur die nötigsten Einstellungen > beinhaltet. Hast du vielleicht Links oder PDF's oder ähnliches welche > mir weiter helfen können? Da habe ich auch nur das Datenblatt, bestenfalls ergänzt um das von dem 90CANxx. Eigentlich steht da soweit auch alles drin. :-) Lukas D. schrieb: > Ich würde pro Sensor eine ID Tag vergeben. MOb2 erhält eine > entsprechende IDMask um nur Nachrichten von Sensor2 aufnehmen zu können. > Das heißst aber, dass ich alle 3 MOb's (für drei Sensoren) zu Beginn > anwählen und konfigurieren muss um die Nachrichten in die jeweiligen > Briefkästen stecken zu können! Das ist jetzt nicht was ich vorgeschlagen habe, funktioniert so aber auch, klar. > Sonst steck ich ja die Nachrichten nur in > MOb1 und weiß ja nicht mehr von welchem Sensor diese ist. Natürlich bekommt man das raus, in den CANIDT Registern steht die ID welche die Message-Box konkret empfangen hat. Das werte ich normalerweise nur nicht aus, weil ich die Maske so einstelle das nur eine einzige Botschaft von der Message-Box angenommen wird. Wobei, das liest sich gerade so, als ob Mob1 alles empfangen soll und Mob2 nur einen Teil, sowas würde nicht funktionieren oder nur zufällig mal, da Mob1 eine höhere Priorität hat als Mob2. Lukas D. schrieb: >> Nein, das geht nicht, man kann immer nur eine Message-Box auswählen. > > Wie mach ich das dann? > > Ich hab noch nicht ganz verstanden wie und wann ich die MOb's anwähle. Die werden einfach jedes Mal bevor man sie benutzen will ausgewählt. Wie so ein Büro-Rollcontainer dessen Schubladen sich gegenseitig verriegeln, man kommt immer nur an den Inhalt einer Schublade ran. Im Interrupt muss man also feststellen, welche Message-Box den ausgelöst hat. Und zum Senden muss man auf die Umstellen in die man Daten packen will. Lukas D. schrieb: > Im Fortlauf hätte ich dann in der ISR drei if-Schleifen, so wie deine: > Rudolph R. schrieb: >> if(CANSIT2 & (1<<SIT1)) // MOB1 hat ausgelöst > > Ich geh dann immer in die jenige wo gerade eine neue Nachricht ankommt > und kann weiterwursteln. Keine Schleifen sondern Abfragen, aber ja. Zur Sicherheit teste ich da auch jedes Bit das auslösen könnte:
1 | ISR (CAN_INT_vect) |
2 | { |
3 | uint8_t canpage; |
4 | |
5 | canpage = CANPAGE; // save canpage |
6 | |
7 | if(CANSIT2 & (1<<SIT1)) // MOB1 |
8 | { |
9 | CANPAGE = (1<<4); // select MOB1 |
10 | CANSTMOB &= ~(1<<RXOK); // clear interrupt flag |
11 | ... |
12 | |
13 | CANCDMOB = (1<<CONMOB1) | (1<<DLC3); // set to receive, 8 bytes in message |
14 | } |
15 | |
16 | if(CANSIT2 & (1<<SIT2)) // MOB2 |
17 | { |
18 | CANPAGE = (2<<4); // select MOB2 |
19 | CANSTMOB &= ~(1<<RXOK); // clear interrupt flag |
20 | ... |
21 | |
22 | CANCDMOB = (1<<CONMOB1) | (1<<DLC3); // set to receive, 8 bytes in message |
23 | } |
24 | |
25 | CANPAGE = canpage; // restore canpage |
26 | } |
Eigentlich kann das gar nicht passieren, dass zwei Auslösen, dafür müsste ja der Interrupt länger blockiert sein, aber so ist es "sicherer" und kostet gegenüber "else if()" ja quasi nichts.
Lukas D. schrieb: > Das heißst aber, dass ich alle 3 MOb's (für drei Sensoren) zu Beginn > anwählen und konfigurieren muss um die Nachrichten in die jeweiligen > Briefkästen stecken zu können! Sonst steck ich ja die Nachrichten nur in > MOb1 und weiß ja nicht mehr von welchem Sensor diese ist. Dein Bild vom CAN-Bus ist wohl etwas verzerrt. Vergiss mal die MOBs und sieh dir an wie CAN allgemein funktioniert: Die Unterscheidung einzelner Nachrichten erfolgt immer über die CAN-ID. Man wertet die empfangene CAN-ID aus und weiß somit welche Daten diese CAN-Botschaft enthält, egal aus welcher MOB die Botschaft stammt. Dein Weg über MOBs die nur immer eine bestimmte ID empfangen ist ein Holzweg. Lukas D. schrieb: > Ich hab noch nicht ganz verstanden wie und wann ich die MOb's anwähle. Wurde eine CAN-Botschaft komplett empfangen so wird ein CAN-Interrupt ausgelöst. In diesem CAN-Irq schaut man dann nach welches MOB die neue Botschaft enthält (den Irq ausgelöst hat), liest dieses MOB aus und setzt es wieder zurück damit es für die nächsten Botschaften wieder frei ist.
Rudolph schrieb: > ISR (CAN_INT_vect) > { > uint8_t canpage; > > canpage = CANPAGE; // save canpage > > if(CANSIT2 & (1<<SIT1)) // MOB1 > { > CANPAGE = (1<<4); // select MOB1 > CANSTMOB &= ~(1<<RXOK); // clear interrupt flag > ... > > CANCDMOB = (1<<CONMOB1) | (1<<DLC3); // set to receive, 8 bytes in > message > } > > if(CANSIT2 & (1<<SIT2)) // MOB2 > {.... Wann ist " if(CANSIT2 & (1<<SIT1)) // MOB1 " erfüllt? Ist im gesendeten Farme doch ein Info zum MOb hinterlegt? Also wenn ich einen Nachricht aus MOb1 des Sensors sende ist dann im Frame hinterlegt das empfangsseitig in MOb1 agbelegt werden soll? Ich seh die klare zuordnung noch nicht. Muss ich nicht in " void init_can_generell(void) " doch alle MOb's, welche ich brauchen werde, anwählen und deklarieren, damit in der ISR deine if-Abfrage funktioniert?
Lukas D. schrieb: > Wann ist " if(CANSIT2 & (1<<SIT1)) // MOB1 " erfüllt? Na, wenn auf dem CAN-Bus eine Botschaft war die zu den Filter-Einstellungen der Message-Box passt und somit als gültig empfangen wurde. > Ist im gesendeten Farme doch ein Info zum MOb hinterlegt? Nein, gar nicht, es gibt nur Message-IDs zum auseinanderhalten auf dem CAN. Es gibt ja auch schon mal nicht "den CAN-Controller", je nach µC Familie und/oder Hersteller funktionieren die nach aussen ganz unterschiedlich. Auch wenn am Ende der Datenstrom auf dem CAN gleich ist. > Muss ich nicht in " void init_can_generell(void) " doch alle MOb's, > welche ich brauchen werde, anwählen und deklarieren, damit in der ISR > deine if-Abfrage funktioniert? Wenn Du mit mehreren Message-Boxen senden und empfangen möchtest, dann musst Du die auch in der Init Funktion alle entsprechend einstellen, ja.
Danke für euren Einsatz. Ich probier übers Wochenende bissl rum und melde mich dann nochmal. Grüße, Lukas
Hallo, wenn ich das jetzt richtig geblickt habe muss die CAN-Einstellung so aussehen, wenn ich jedem Sensor ein MOb zuweißen möchte! void init_can_generell(void) { uint8_t i,j; CANGCON = (1<<SWRES); // Can-Controller mit Hardware Reseted. //CANGSTA = (1<<ENFG); // Enable CAN-Controller - nope, das zeigt an, dass an ist for (i=0; i<6; i++) // alle MOb's zurücksetzen. { CANPAGE = (i<<4); // select MOb-Number CANCDMOB = 0x00; // disable MOb, transmission and reception CANSTMOB = 0x00; // clear status CANIDT1 = 0x00; // clear ID CANIDT2 = 0x00; CANIDT3 = 0x00; CANIDT4 = 0x00; CANIDM1 = 0x00; // clear mask CANIDM2 = 0x00; CANIDM3 = 0x00; CANIDM4 = 0x00; for(j=0; j<8; j++) { CANMSG = 0x00; // Daten zurücksetzen } } CANBT1 = 0x0E; // Baudrate mit 250 KBaud bei fCLKio = 16MHz festgelegt CANBT2 = 0x04; // ... CANBT3 = 0x13; // ... CANGCON = (1<<ENASTB); // CAN-Channel wechselt in enable mode wenn 11 recessive Bits gelesen wurden // Einstellungen für MOb0 --> Nachrichten von Sensor1 werden hier aufgenommen CANPAGE = 0x00; // Mob0 anwählen //nach einer bestimmten ID in MOb0 filtern ( ID = 00000000111) CANIDM1 = 0xFF; // kein Bit der ID ist für das Filtern vernachlässigbar CANIDM2 = 0xE0;// ... CANIDM4 = (1<<IDEMSK);// ... CANIDT1 = 0x00; // Nach IDTag = 00000000111 filtern CANIDT2 = 0x70; // ... CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message // Einstellungen für MOb1 --> Nachrichten von Sensor2 werden hier aufgenommen CANPAGE = 0x10; // Mob1 anwählen //nach einer bestimmten ID in MOb1 filtern ( ID = 00001110000) CANIDM1 = 0xFF; // kein Bit der ID ist für das Filtern vernachlässigbar CANIDM2 = 0xE0;// ... CANIDM4 = (1<<IDEMSK);// ... CANIDT1 = 0x0E; // Nach IDTag = 00001110000 filtern CANIDT2 = 0x00; // ... CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message // Einstellungen für MOb2 --> Nachrichten von Sensor3 werden hier aufgenommen CANPAGE = 0x20; // Mob2 anwählen //nach einer bestimmten ID in MOb2 filtern ( ID = 11100000000) CANIDM1 = 0xFF; // kein Bit der ID ist für das Filtern vernachlässigbar CANIDM2 = 0xE0;// ... CANIDM4 = (1<<IDEMSK);// ... CANIDT1 = 0xE0; // Nach IDTag = 11100000000 filtern CANIDT2 = 0x00; // ... CANCDMOB = (1<<CONMOB1) | (1<<DLC0); // set to receive, 1-byte in message // Einstellungen für ISR CANGIE = (1<<ENIT) | (1<<ENRX); // enable receive interrupt CANIE1 = 0x00; CANIE2 = 0b00000111; // enable ISR wenn MOb0/1/2 beschrieben wird CANSIT1 = 0x00; CANSIT2 = 0x00; } Grüße, Luk
Bitte deinen Programmcode als Datei im Format .c anhängen. Der Thread wird ja sonst ellenlang.
Hast recht, werd ich in Zukunft machen! Für die Vollständigkeit, so geht es!
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.