Forum: Mikrocontroller und Digitale Elektronik CAN-Nachrichten empfangen


von LARA (Gast)


Lesenswert?

Hallo!
Ich moechte mithilfe eines ATMega128 und eines MPC2510 einen CAN-Bus
abhoeren und abh. von den eintreffenden Nachrichten die Ausgaenge
steuern. Das bedeutet, ich muss CAN-Nachrichten lesen koennen...
Ich habe auch schon im Netz gestoebert und mit den gefundenen
Beitraegen versucht mir ein Programm zusammmen zu basteln, aber so ganz
klar ist mir das ganze noch nicht, vor allem das Einlesen der
CAN-Nachrichten


/**************************** importierte Header-Files
**********************/
#include <mega128.h>
#include <stdio.h>
#include <delay.h>
#include <mcp2510.h>

#define MISO 3          //ist Eingang
#define MOSI 2          //ist Ausgang
#define SCK 1           //ist Ausgang
#define SS 0            //ist Ausgang

//SPI Control Register SPCR
#define SPIE 7
#define SPE 6
#define DORD 5
#define MSTR 4
#define CPOL 3
#define CPHA 2
#define SPR1 1
#define SPR0 0

//SPI Status Register SPSR
#define SPIF 7
#define WCOL 6


/**************************** Funktionsdeklarationen
*************************/
void init_SPI (void);
void configure_mcp (void);
void reset_mcp (void);
void write_mcp (unsigned char adress, unsigned char value);
unsigned char read_mcp(unsigned char adress);



//Initialisierung des Serial Peripheral Interfaces
void init_SPI (void)
{
        DDRB = (1<<MOSI) | (1<< SCK) | (1<<SS);         //MOSI, SCK, SS
als Ausgang (-> DDRB=0x07)
        PORTB |= (1<<SS);                               //Pull-up an SS
(mcp disable) (PORTB.0=1);
        SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);   // SPI Controll
Register (-> SPCR=0x51)
                                                        //| (1<<SPIE);
Interruptfreigabe
}

void reset_mcp (void)
{
  PORTB &= ~(1<<SS);                              //CS auf LOW setzen,
SPI Übertragung einleiten (-> PORTB.0=0)
  SPCR=RESET_MCP;                                 //Reset Instruction
senden (0xC0)
  while (!(SPSR && 0x80));
        while (!(SPSR && (1<<SPIF)));                    //warten bis
BYTE (SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  PORTB |= (1<<SS);                                //CS auf HIGH setzen,
Übertragung beendet (-> PORTB.0=1)
}


void configure_mcp (void)
{
        reset_mcp();                                    //mcp in den
Grundzustand setzen
        write_mcp(CANCTRL, 0x85);                       //Configuration
Mode, CLKOUT enable, System Clock/2
        write_mcp(CNF1, 0x05);                          //CNF1, CNF2,
CNF3 legen 83,3 kbaud @ 8 MHz fest
        write_mcp(CNF2, 0x90);
        write_mcp(CNF3, 0x02);
        write_mcp(CANCTRL, 0x45);                       //Loopback
Mode, CLKOUT enable, System Clock/2
}

//Beschreiben der MPC-Register
void write_mcp (unsigned char adress, unsigned char value)
{
  PORTB &= ~(1<<SS);                              //CS auf LOW setzen,
SPI Übertragung einleiten (-> PORTB.0=0)
  SPCR=WRITE_MCP;                                 //Write Instruction
senden (0x02)
  while (!(SPSR && (1<<SPIF)));                    //warten bis BYTE
(SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  SPDR=adress;                                    //Addresse senden
        while (!(SPSR && (1<<SPIF)));                    //warten bis
BYTE (SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  SPDR=value;                                     //Wert senden
  while (!(SPSR && (1<<SPIF)));                    //warten bis BYTE
(SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  PORTB |= (1<<SS);                               //CS auf HIGH setzen,
Übertragung beendet (-> PORTB.0=1)
}

//Auslesen der MPC-Register
unsigned char read_mcp(unsigned char adress)
{
  unsigned char spidata;

  PORTB &= ~(1<<SS);                              //CS auf LOW setzen,
SPI Übertragung einleiten (-> PORTB.0=0)
  SPCR=READ_MCP;                                  //Read Instruciotn
senden (0x03)
  while (!(SPSR && (1<<SPIF)));                    //warten bis BYTE
(SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  SPDR=adress;                                    //Addresse senden
  while (!(SPSR && (1<<SPIF)));                    //warten bis BYTE
(SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  SPDR=0xAA;                                      //Dummy-Byte senden
  while (!(SPSR && (1<<SPIF)));                    //warten bis BYTE
(SPIF-Flag gesetzt) gesendet wurde (Ende Übertragung)
  spidata=SPDR;                                   //Daten aus SPI
abholen
  PORTB |= (1<<SS);                               //CS auf HIGH setzen,
Übertragung beendet (-> PORTB.0=1)
  return (spidata);
}


/**************************** Hauptprogramm
**********************************/


int main( void )
{

  DDRC=0x0F;                      //C.0, C.1, C.2, C.3 sind Eingang,
C.4, C.5, C.6, C.7 sind Ausgang
  DDRB=0x0F;                      //B.0, B.1, B.2, B.3 sind Eingang,
B.4, B.5, B.6, B.7 sind Ausgang

  init_SPI();

  while(1)
  {

  }


}



Folgende Punkte sind fuer mich noch vollkommen unklar:
* Wie kann ich die (richtigen) CAN-Nachrichte empfangen??? Wie frage
ich den Identifier ab?
* Was ist besser: Polling oder Interrupt?? und wie werden diese
generiert??
* sind CNF1, 2 und 3 richtig festgelegt???
* Wofuer benoetigt der MCP einen eigenen Quarz, wo er doch die
Taktleitung des Mega128s hat?

Wie man leicht merken kann, ist die Verwirrung noch recht gross, daher
bin ich sehr dankbar, wenn mir der ein oder andere einen Tipp geben
kann um ein bisschen Licht in die Dunkelheit zu bringen!

Herzlichen Dank und viele Gruesse
LARA

von inoffizieller WM-Rahul (Gast)


Lesenswert?

http://www.mikrocontroller.net/forum/list-1-1.html?filter=mcp2510

Vielleicht hilft dir das. Deinen Code habe ich mir nicht angeguckt.

von crazy horse (Gast)


Lesenswert?

habe auch keine Lust, mich durchzuquälen.
MCP2510 kenne ich nicht, ist der kompatibel zum 2515?

Folgende Punkte sind fuer mich noch vollkommen unklar:
* Wie kann ich die (richtigen) CAN-Nachrichte empfangen??? Wie frage
ich den Identifier ab?

Dabei gibts 2 Strategien.
Einmal kannst du das Akzeptanz-Filter im MCP programmieren, du erhälst
also überhaupt nur die Botschaften, die dieses Filter passieren können.
Der Rest verschwindet im Nirwana. Vorteil: du brauchst nicht jede
empfangene Botschaft auszulesen und zu interpretieren.
Ansonsten: alles empfangen und die gewünschten Identifier selbst
ausfiltern.
in der Art:

if  (CAN0_message_received)
       {CAN0_message_received=0;
       #asm ("cli")
       switch (message1.id) {
       case 0x280: {Heizung[0]=message1;
                    process_heizung1();
                    break;
                    }
       case 0x289:  {Heizung[1]=message1;
                    process_heizung2();
                    break;
                    }
       case 0x298:  {Heizung[2]=message1;
                    process_heizung3();
                    break;
                    }


                    default: break;
           }   //end switch
       }
       #asm ("sei")
Der Empfang erfolgt im Interrupt und wird in den struct CANMessage
geschrieben (besteht aus int id, char rtr, char length und data[8].
Anhand von .id wird entschieden, was passieren soll. Botschaften, die
zwar vom CAN-Controller kommen, aber nicht in obiger switch-Anweisung
verarbeitet werden, werden mit der nächsten Nachricht überschrieben.

* Was ist besser: Polling oder Interrupt?? und wie werden diese
generiert??
Auf jeden Fall Interrupt. Das Interruptsignal erzeugt der
CAN-Controller, in der ISR werden dann alle rel. Daten gelesen und das
Interruptflag des CAN-Controllers gelöscht.


* sind CNF1, 2 und 3 richtig festgelegt???
Bei Microchip gibts ein schönes Programm, welches dir alle
Einstellungen berechnet.

* Wofuer benoetigt der MCP einen eigenen Quarz, wo er doch die
Taktleitung des Mega128s hat?
Er benötigt keinen eigenen Quarz, aber einen eigenen Takt. Mit
Taktleitung meinst du sicher die der SPI? Das funktioniert natürlich
nicht. Ich setz meist den Quarz an den MCP, dessen (programmierbarer)
clk_out versorgt dann den AVR. Manchmal ist es aber nötig, getrennte
Quarze einzusetzen, wenn z.B. auf dem MC auch UART-Kommunikation
höherer Baudrate läuft. Dann bekommt der MC einen Baudratenquartz, der
CAN einen für CAN passenden.

von LARA (Gast)


Lesenswert?

Hallo nochmals!
Ehrlich gesagt, verstehe ich es immernoch nicht.
Ich habe folgende Funktionen (die ich auch soweit verstehe und die in
dem Quellcode oben umgesetzt sind) generiert:
*void init_SPI (void)
*void reset_mcp (void)
*void configure_mcp (void)
*void write_mcp (unsigned char adress, unsigned char value)
*unsigned char read_mcp (unsigned char adress)

Wie kann ich nun diese verwenden, um die Nachrichten ueber die SPI die
Nachrichten an den Controller zu schicken? @Crazy Horse: leider ist mir
nicht so klar, wie ich das sw-befehlsmaessig umsetzen soll... warum
machst Du "CAN0_message_received=0"??
Mir fehlt total der Ansatz fuers Hauptprogramm!

Danke nochmals allen, die mich vorm Verzweifeln retten ;-)
Gruss
LARA

von crazy horse (Gast)


Lesenswert?

CAN0_message_received ist nur ein flag (bit), welches dem Hauptprogramm
anzeigt, dass eine Botschaft auf dem CAN0 (stammt aus einem Gerät mit 3
CAN-Controllern) angekommen ist.

Eh wir das jetzt alles Schritt für Schritt durchkauen, empfehle ich dir
folgende Seite:
http://www.kreatives-chaos.com/
Wenn du es dann prinzipiell verstanden hast, können wir gerne über
Einzelheiten weiterreden.

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.