Serie inDetail - komplexe Themen verständlich dargestellt

Senden eines CAN Frames

Zum Senden eines CAN Frames sind 3 Schritte notwendig.

  1. CAN Informationen in die entsprechenden Stellen des Tx-Buffers auf dem Arduino schreiben. Dazu dienen die set-Funktionen denen man eine SID oder EID übergeben kann. Damit werden auch die Nutzdaten übertragen und angegeben wie viele Nutzdaten es sind oder ob es sich um einen Remote Frame handelt.
  2. Den vorbereiteten Buffer mit seinen bis zu 13 Bytes auf den MCP2515 übertragen.
  3. Das TX Request Bit (TXREQ im Register TXB_CONTR) auf '1' setzen. Anschließend wird vom MCP2515 die Nachricht selbstständig versendet. Bei ausbleibendem Bestätigung von einem Empfänger wird der Sendeversuch mehrfach wiederholt. Erst wenn das TXREQ bit vom MCP2515 wieder auf '0' gesetzt wurde ist die Nachricht erfolgreich versendet worden.

Beispiel: Senden eines CAN Standard Frame mit SID (Standard Identifier)

Über den TX-Buffer 0 werden 3 Bytes (50,100 und 200) mit der Frame ID (SID=2000) versendet. Die CRC Checksumme am Ende des Frames wird vom MCP2515 selbstständig berechnet und versendet. Das letzte Bit nach der CRC Checksumme ist das Acknowledge bit welches von einem Empfangsknoten gesendet wird und die Übertragung abschließt.

CAN.setSID(0, 2000); // Übertrag die 11'stellige SID in den gewählten TX Buffer (bufferNr, SID) CAN.setPayload(50, 100, 200); // Überträgt bis zu 8 Byte Nutzdaten (bufferNr, D0-D7) CAN.setDLC(0, 3); // Anzahl der Nutzdaten an die übertragen werden (bufferNr, DLC)) CAN.sendTXbuffer(0); // Überträgt den fertigen Buffer auf den MCP2515 und versendet die Nachricht
Standard Frame mit SID

Beispiel: Senden eines CAN Standard Frame mit EID (Extended Identifier)

Über den TX-Buffer 1 wird 1 byte Nutzdaten (=50) mit der Frame ID (EID=40000) versendet. Durch dei Auswahl der SetEID() Methode wird auch das EXIDE Bit zur Kennzeichnung des Frames als Extended Identifier Nachricht gesetzt.

CAN.setEID(1, 40000); // Übertrag die 29'stellige EID in den gewählten TX Buffer (bufferNr, EID) CAN.setPayload(50); // Überträgt bis zu 8 Byte Nutzdaten (bufferNr, D0-D7) CAN.setDLC(1, 1); // Anzahl der Nutzdaten an die übertragen werden (bufferNr, DLC)) CAN.sendTXbuffer(1); // Überträgt den fertigen Buffer auf den MCP2515 und versendet die Nachricht
Standard Frame mit EID

Beispiel: Senden eines Remote Request Frame mit SID

CAN.setSID(0, 2000); // Übertrag die 11'stellige SID in den gewählten TX Buffer (bufferNr, SID) CAN.setDLC(0, 3, 1); // Anzahl der Nutzdaten an die übertragen werden (bufferNr, DLC, RemoteRequest) CAN.sendTXbuffer(0); // Überträgt den fertigen Buffer auf den MCP2515 und versendet die Nachricht
Request Frame mit SID

Beispiel: Senden eines CAN Standard Frame mit EID (Extended Identifier)

Über den TX-Buffer 1 wird 1 byte Nutzdaten (=50) mit der Frame ID (EID=40000) versendet. Durch dei Auswahl der SetEID() Methode wird auch das EXIDE Bit zur Kennzeichnung des Frames als Extended Identifier Nachricht gesetzt.

CAN.setEID(0, 2000); // Übertrag die 29'stellige EID in den gewählten TX Buffer (bufferNr, EID) CAN.setDLC(0, 3, 1); // Anzahl der Nutzdaten an die übertragen werden (bufferNr, DLC, RemoteRequest) CAN.sendTXbuffer(0); // Überträgt den fertigen Buffer auf den MCP2515 und versendet die Nachricht
Extended Identifier Frame mit EID
Klasse "MCP25215" mit den Methoden zum Senden eines CAN Frames #include "SPI.h" /* Erstellen eines eigenen Datentyps 'Buffer' mit den gleichen Namen und der gleichen Reihenfolge wie die * entsprechenden Buffer im MCP2515 (Kopie der 5 Buffer 3x Tx und 2xRx) */ struct Buffer{ byte SIDH; byte SIDL; byte EID8; byte EID0; byte DLC; byte D0, D1, D2, D3, D4, D5, D6, D7; }; class MCP2515 { private: byte CS; // Speichern des von Konstruktor übertragenen 'Chip Select' Pins Buffer RXB0, RXB1, TXB0, TXB1, TXB2; // Byte-Container vom oben definierten Typ 'Buffer' void reset(); // Reset des MCP2515 (= wie VCC Unterbrechung) byte registerRead(byte); // Liest ein Registerinhalt (regAdr) void registerWrite(byte, byte); // Beschreibt ein Register (regAdr, daten) void modifyBits(byte, byte, byte); // Verändert einzelne Bits des Registers (regAdr, maske, daten) void sendRTS(byte); // 'Request to Send' eines TX Buffers (bufferNr) void setMode(byte); // 0=Normal Mode, 1=Sleep , 2=Loopback , 3= Listen , 4= Config void readRXbuffer(byte); // Auslesen und quittieren eines RX/Empfangs Buffer (bufferNr) void loadTXbuffer(byte); // Übertragen eines kompletten Buffers auf den MCP2515 (bufferNr) public: // Konstruktor (Initialisierungsfunktion) MCP2515(byte cs = 10) { SPI.begin(); SPI.setDataMode(SPI_MODE0); // oder SPI_MODE3 SPI.setClockDivider(SPI_CLOCK_DIV4); // max. 10 Mhz SPI.setBitOrder(MSBFIRST); CS = cs; // Ein andere CS Pin kann optional übergeben werden pinMode(CS, OUTPUT); // Chip Select Pin für die SPI Schnittstelle konfigurieren // Befehle zum Senden von Nachrichten void setSID(byte, unsigned int); // Schreibt die SID in den gewählten Buffer (bufferNr, SID) void setEID(byte, unsigned long); // schreibt die EID in den gewählten Buffer (bufferNr, EID) void setPayload(byte, byte, byte, byte, byte, byte, byte, byte, byte); // schreibt die Nutzdaten void setDLC(byte, byte, bool); // (bufferNr, anzahlPayload, RemoteFrame) void sendTXbuffer(byte); // sendet den gewählten Buffer auf den CAN Bus (bufferNr) }; //// PRIVATE METHODS ////////////////////////////////////////////////////////////////////////////////// /* Zur besseren Übersichtlichkeit werden die PRIVATE Funktion hier nicht mehr angezeigt */ // PUBLIC METHODEN /////////////////////////////////////////////////////////////////////////////////// void MCP2515::setSID(byte bufferNr, unsigned int SID) { /* Funktion zum setzen der SID in den entsprechenden Buffer auf dem Arduino. Der Funktion wird die * Buffer-Nummer TXB0 oder TXB1 und die 11stellige SID übergeben. Werden mehr stellen angegeben erfolgt * durch die anfängliche if-Abfrage eine Kürzung auf max 11 Stellen. Durch die switch Abfrage wird * festgelegt welcher Buffer übertragen wird. * Durch die Bitverschiebung nach links wird ein vorhandenes Extended Identifier Bit (EXIDE) automatisch * auf 0 gesetzt. Die beiden Register EID8 und EID0 werden nicht benötigt und zur besseren * Übersichtlichkeit auf 0 gesetzt. */ if (SID > 2047) SID = 2047; // SID max 11 Stellen (=2047) switch (bufferNr) { case 0: TXB0.SIDH = SID >> 3; TXB0.SIDL = SID << 5; TXB0.EID8 = 0; TXB0.EID0 = 0; break; case 1: TXB1.SIDH = SID >> 3; TXB1.SIDL = SID << 5; TXB1.EID8 = 0; TXB1.EID0 = 0; break; default: TXB2.SIDH = SID >> 3; TXB2.SIDL = SID << 5; TXB2.EID8 = 0; TXB2.EID0 = 0; } } //---------------------------------------------------------------------------------------------------- void MCP2515::setEID(byte bufferNr, unsigned long EID) { /* Funktion zum setzen der EID in den entsprechenden Buffer auf dem Arduino. Der Funktion wird die * Buffer-Nummer TXB0 oder TXB1 und die 29stellige EID übergeben. Werden mehr stellen angegeben erfolgt * durch die anfängliche if-Abfrage eine Kürzung auf max 29 Stellen. Durch die switch Abfrage wird * festgelegt welcher Buffer übertragen wird. * Zur Aufnahme der EID werden auch die Register der SID verwendet. Zusätzlich zur Aufteilung auf 8 Bit * Abschnitte wird mit der Funktion auch das Extended Identifier Bit (EXIDE [3] in Reg SIDL) gesetzt. */ if (EID > 536870911) EID = 536870911; // EID max 29 Stellen (=536870911) switch (bufferNr) { case 0: TXB0.SIDH = EID >> 21; // EID28-EID21 // EID20-EID18 + EXIDE + EID17-EID16 TXB0.SIDL = (EID >> 13 & B11100000) | B00001000 | (EID >> 16 & B00000111) ; TXB0.EID8 = EID >> 8; //EID15-EID8 TXB0.EID0 = EID; //EID7-EID0 break; case 1: TXB1.SIDH = EID >> 21; // EID28-EID21 // EID20-EID18 + EXIDE + EID17-EID16 TXB1.SIDL = (EID >> 13 & B11100000) | B00001000 | (EID >> 16 & B00000111) ; TXB1.EID8 = EID >> 8; //EID15-EID8 TXB1.EID0 = EID; //EID7-EID0 break; default: TXB2.SIDH = EID >> 21; // EID28-EID21 // EID20-EID18 + EXIDE + EID17-EID16 TXB2.SIDL = (EID >> 13 & B11100000) | B00001000 | (EID >> 16 & B00000111) ; TXB2.EID8 = EID >> 8; //EID15-EID8 TXB2.EID0 = EID; //EID7-EID0 } } //---------------------------------------------------------------------------------------------------- void MCP2515::setPayload(byte bufferNr, byte D0, byte D1 = 0, byte D2 = 0, byte D3 = 0, byte D4 = 0, byte D5 = 0, byte D6 = 0, byte D7 = 0) { /* Mit dieser Funktion werden die Payload Daten übertragen. Der Funktion müssen einer der der TX * Buffer Nummern übergeben werden sowie die entsprechenden Datenbytes. Bis zu 8 Datenbytes können * der Funktion übergeben werden. Eines muss angegeben werden. D1-D7 sind optional und werden bei falls * nicht angegeben zu 0. */ switch (bufferNr) { case 0: TXB0.D0 = D0; TXB0.D1 = D1; TXB0.D2 = D2; TXB0.D3 = D3; TXB0.D4 = D4; TXB0.D5 = D5; TXB0.D6 = D6; TXB0.D7 = D7; break; case 1: TXB1.D0 = D0; TXB1.D1 = D1; TXB1.D2 = D2; TXB1.D3 = D3; TXB1.D4 = D4; TXB1.D5 = D5; TXB1.D6 = D6; TXB1.D7 = D7; break; default: TXB2.D0 = D0; TXB2.D1 = D1; TXB2.D2 = D2; TXB2.D3 = D3; TXB2.D4 = D4; TXB2.D5 = D5; TXB2.D6 = D6; TXB2.D7 = D7; break; } } //---------------------------------------------------------------------------------------------------- void MCP2515::setDLC(byte bufferNr, byte anzahlNutzdaten, bool RTR = 0) { /* Die Funktion übertragt die Anzahl der Nutzdaten in den entsprechende TXBx Buffer. * Maximal können 8 Nutzdaten mit dem MCP2515 übertragen werden. Damit auch keine größere Anzahl * angegeben werden kann wird durch die if-Abfrage sichergestellt. * In der Grundeinstellung wird ein Standardframe gesendet. Das RTR Bit (Remote Transmission Request) * ist daher 0. Soll die Nachricht als Remote Frame gesendet werden muß das RTR Bit auf 1 gesetzt werden. */ if (anzahlNutzdaten > 8) anzahlNutzdaten = 8; switch (bufferNr) { case 0: TXB0.DLC = anzahlNutzdaten | RTR << 6; break; case 1: TXB1.DLC = anzahlNutzdaten | RTR << 6; break; default: TXB2.DLC = anzahlNutzdaten; } } //---------------------------------------------------------------------------------------------------- void MCP2515::sendTXbuffer(byte bufferNr) { /* Läd zunächst den ausgewählten TX-Buffer vom Arduino in die gleichnamigen Register des MCP2515. * Anschließend wird mit 'sendRTS()' die Nachricht über CAN versendet. Die sendRTS Argumente müssen * der Buffer Nummer angepasst werden. * (lt. Datenblatt: TXB0 = 1 | TXB1 = 2 | TXB2 = 4 | TXB0/TXB1 = 3 | TXB0/TXB1/TXB2 = 7) */ switch (bufferNr) { case 0: loadTXbuffer(bufferNr); sendRTS(1); break; case 1: loadTXbuffer(bufferNr); sendRTS(2); break; default: loadTXbuffer(bufferNr); sendRTS(4); } }