Forum: Mikrocontroller und Digitale Elektronik CAN funktioniert , aber nicht im vollen Umfang


von Lukas D. (lukdi)


Angehängte Dateien:

Lesenswert?

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

von temp (Gast)


Lesenswert?

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...

von Rudolph (Gast)


Lesenswert?

Yup, mach mal Test-Code mit dem Problem und stell den ein, ich benutze 
die ATMega16M1 schon etwas länger.

von Lukas D. (lukdi)


Lesenswert?

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 
######################################################################## 
######################################################################## 
######################################################################## 
##
// 
######################################################################## 
######################################################################## 
######################################################################## 
##

von Rudolph R. (rudolph)


Lesenswert?

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? :-)

von Lukas D. (lukdi)


Lesenswert?

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

von Rudolph (Gast)


Lesenswert?

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.

von Lukas Dinauer (Gast)


Lesenswert?

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

von Rudolph R. (rudolph)


Lesenswert?

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.

von Lukas D. (lukdi)


Lesenswert?

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

von Lukas D. (lukdi)


Lesenswert?

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.

von Rudolph (Gast)


Lesenswert?

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.

von Thomas F. (igel)


Lesenswert?

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.

von Lukas D. (lukdi)


Lesenswert?

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?

von Rudolph (Gast)


Lesenswert?

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.

von Lukas D. (lukdi)


Lesenswert?

Danke für euren Einsatz. Ich probier übers Wochenende bissl rum und 
melde mich dann nochmal.

Grüße,

Lukas

von Lukas D. (lukdi)


Lesenswert?

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

von Thomas F. (igel)


Lesenswert?

Bitte deinen Programmcode als Datei im Format .c anhängen.
Der Thread wird ja sonst ellenlang.

von Lukas D. (lukdi)


Lesenswert?

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
Noch kein Account? Hier anmelden.