[gelöst] Arduino CAN-Shield Interrupt nur bei bestimmter CAN-ID

Hallo,

ich habe das CAN-Shield mit einem Arduino UNO und möchte das der MCP2515 nur bei einer bestimmten ID einen Interrupt auslöst.

In der CAN-Lib sind zwar Beispiele (auch für IRQ) aber nicht das was ich suche/brauche.

Wie sind die Settings wenn der MCP nur beim Empfang der ID 0x743 einen Interrupt auslösen soll?

Gruß
Jackson

Schaue mal bei UNO - Mega - Teensy mittels CAN-Bus verbinden, ob es Dir hilft.

noiasca:
brauchst du generell nur die eine Message? Dann müsste das doch mit entsprechenden Filtern und Filtermaske funktionieren.

Da eventuell noch eine zweite oder dritte ID dazu kommen könnte würde ich es gern schon mit den Message buffern machen.
Ich kenne das von modernen MCUs mit integriertem CAN das man dort einfach einen Message Buffer definiert auf welche ID er reagiert und einen IRQ auslöst.

agmue:
Schaue mal bei UNO - Mega - Teensy mittels CAN-Bus verbinden, ob es Dir hilft.

Da die eine andere Library nutzt hilft es leider nicht...

Ich nutze die: GitHub - Seeed-Studio/Seeed_Arduino_CAN: Seeed Arduino CAN-BUS library - MCP2518FD&MCP2515&MCP2551

mit deren Beispielen

// *************************************************************************************************************
// Es soll nur auf ID 0x743 und ID 0x242 ein IRQ ausgelöst werden der dann in der Main ausgewertet werden soll
// *************************************************************************************************************

// demo: CAN-BUS Shield, receive data with interrupt mode, and set mask and filter
//
// when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
// loovee, 2014-7-8

#include <SPI.h>
#include "mcp_can.h"

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
  #define SERIAL SerialUSB
#else
  #define SERIAL Serial
#endif

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
    SERIAL.begin(115200);

    while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");

    attachInterrupt(0, MCP2515_ISR, FALLING); // start interrupt


    /*
     * set mask, set both the mask to 0x3ff
     */
    CAN.init_Mask(0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
    CAN.init_Mask(1, 0, 0x3ff);


    /*
     * set filter, we can receive id from 0x04 ~ 0x09
     */
    CAN.init_Filt(0, 0, 0x04);                          // there are 6 filter in mcp2515
    CAN.init_Filt(1, 0, 0x05);                          // there are 6 filter in mcp2515

    CAN.init_Filt(2, 0, 0x06);                          // there are 6 filter in mcp2515
    CAN.init_Filt(3, 0, 0x07);                          // there are 6 filter in mcp2515
    CAN.init_Filt(4, 0, 0x08);                          // there are 6 filter in mcp2515
    CAN.init_Filt(5, 0, 0x09);                          // there are 6 filter in mcp2515

}

void MCP2515_ISR()
{
    flagRecv = 1;
}

void loop()
{
    if(flagRecv)                   // check if get data
    {

        flagRecv = 0;                // clear flag
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        SERIAL.println("\r\n------------------------------------------------------------------");
        SERIAL.print("Get Data From id: ");
        SERIAL.println(CAN.getCanId());
        for(int i = 0; i<len; i++)    // print the data
        {
            SERIAL.print("0x");
            SERIAL.print(buf[i], HEX);
            SERIAL.print("\t");
        }
        SERIAL.println();

    }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

Jackson0:
Ich nutze die: GitHub - Seeed-Studio/Seeed_Arduino_CAN: Seeed Arduino CAN-BUS library - MCP2518FD&MCP2515&MCP2551

Da ist auch ein MCP2515 verbaut, sollte also von den Masken und Filtern passen.

Ich sende die Ids 0x743, 0x242 und 0x102, der Empfänger läßt nur 0x242 und 0x743 durch:

void setup()
{
  Serial.begin(115200);
  pinMode(LEDpin, OUTPUT);

  while (CAN_OK != CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ))  // init can bus : masks and filters disabled, baudrate, Quarz vom MCP2551
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");
  CAN0.init_Mask(0, 0, 0x07FF0000);              // Init first mask...
  CAN0.init_Filt(0, 0, 0x07430000);              // Init first filter...
  CAN0.init_Filt(1, 0, 0x02420000);              // Init second filter...

  CAN0.init_Mask(1, 0, 0x07FF0000);              // Init second mask...
  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

Meine Hardware schwingt mit 8 MHz, das muß passen! MCP_STD funktioniert nicht, daher MCP_STDEXT. Ich verwende Polling.

EDIT: 0x242 ergänzt.

Habe die Filter nach deinem Beispiel angepasst (zum Testen mit 0x2C1 und 0x668 weil ich grade nur ein Replayfile habe in dem diese u. a. über einen CAN-Logger gesendet werden)

Obwohl nach deinen Angaben geändert gibt er aber nichts aus.

// *************************************************************************************************************
// Es soll nur auf ID 0x743 und ID 0x242 ein IRQ ausgelöst werden der dann in der Main ausgewertet werden soll
// *************************************************************************************************************

// demo: CAN-BUS Shield, receive data with interrupt mode, and set mask and filter
//
// when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
// loovee, 2014-7-8

#include <SPI.h>
#include "mcp_can.h"

/*SAMD core*/
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
  #define SERIAL SerialUSB
#else
  #define SERIAL Serial
#endif

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
    SERIAL.begin(115200);

    while (CAN_OK != CAN.begin(CAN_500KBPS))              // init can bus : baudrate = 500k
    {
        SERIAL.println("CAN BUS Shield init fail");
        SERIAL.println(" Init CAN BUS Shield again");
        delay(100);
    }
    SERIAL.println("CAN BUS Shield init ok!");

    attachInterrupt(0, MCP2515_ISR, FALLING); // start interrupt

    /*
     * set mask, set both the mask to 0x3ff
     */
    CAN.init_Mask(0, 0, 0x07FF0000);                         // there are 2 mask in mcp2515, you need to set both of them
    CAN.init_Mask(1, 0, 0x07FF0000);

    /*
     * set filter, we can receive id from 0x04 ~ 0x09
     */

    CAN.init_Filt(0, 0, 0x02C10000);                          // there are 6 filter in mcp2515
    CAN.init_Filt(1, 0, 0x06680000);                          // there are 6 filter in mcp2515
    
    CAN.init_Filt(2, 0, 0x02C10000);                          // there are 6 filter in mcp2515
    CAN.init_Filt(3, 0, 0x06680000);                          // there are 6 filter in mcp2515

//    CAN.init_Filt(4, 0, 0x00);                          // there are 6 filter in mcp2515
//    CAN.init_Filt(5, 0, 0x00);                          // there are 6 filter in mcp2515

}

void MCP2515_ISR()
{
    flagRecv = 1;
}

void loop()
{
    if(flagRecv)                   // check if get data
    {

        flagRecv = 0;                // clear flag
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        SERIAL.println("\r\n------------------------------------------------------------------");
        SERIAL.print("Get Data From id: ");
        SERIAL.println(CAN.getCanId());
        for(int i = 0; i<len; i++)    // print the data
        {
            SERIAL.print("0x");
            SERIAL.print(buf[i], HEX);
            SERIAL.print("\t");
        }
        SERIAL.println();

    }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

Jackson0:
Habe die Filter nach deinem Beispiel angepasst ...

Sehe gerade, daß unsere Bibliotheken mit mcp_can.h eingebunden werden, aber wohl doch unterschiedlich sind. Das ist natürlich verwirrend.

Dann eben mit der Bibliothek CAN-BUS_Shield von Seeed-Studio:

 CAN.init_Mask(0, 0, 0x7FF);                         // there are 2 mask in mcp2515, you need to set both of them
  CAN.init_Mask(1, 0, 0x7FF);

  CAN.init_Filt(0, 0, 0x743);                          // there are 6 filter in mcp2515
  CAN.init_Filt(1, 0, 0x242);                          // there are 6 filter in mcp2515

Geht leider auch nicht, sprich es wird kein IRQ ausgelöst.

Dann liegt der Fehler irgendwo anders, bei mir geht Polling und Interrupt.

Mein Empfangssketch:

#include <SPI.h>
#include "mcp_can.h"

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 53;    // Mega2560

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
  Serial.begin(115200);

  while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_8MHz))              // init can bus : baudrate = 500k
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");

  attachInterrupt(0, MCP2515_ISR, FALLING); // start interrupt


  /*
     set mask, set both the mask to 0x3ff
  */
  CAN.init_Mask(0, 0, 0x7FF);                         // there are 2 mask in mcp2515, you need to set both of them
  CAN.init_Mask(1, 0, 0x7FF);

  CAN.init_Filt(0, 0, 0x743);                          // there are 6 filter in mcp2515
  CAN.init_Filt(1, 0, 0x242);                          // there are 6 filter in mcp2515
}

void MCP2515_ISR()
{
  flagRecv = 1;
}

void loop()
{
  //if (CAN_MSGAVAIL == CAN.checkReceive())           // check if data coming
  if(flagRecv)                   // check if get data 
  {
    flagRecv = 0;                // clear flag
    CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

    Serial.print("Get Data From id: 0x");
    Serial.print(CAN.getCanId(), HEX);
    for (int i = 0; i < len; i++) // print the data
    {
      Serial.print("\t0x");
      Serial.print(buf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();

  }
}

Ich sende die Ids 0x743, 0x242 und 0x102, Ausgabe:

</sup> <sup>Enter setting mode success set rate success!! Enter Normal Mode Success!! CAN BUS Shield init ok! Begin to set Mask!! set Mask success!! Begin to set Mask!! set Mask success!! Begin to set Filter!! set Filter success!! Begin to set Filter!! set Filter success!! Get Data From id: 0x743 0x0 0x1 0xC 0x3 0x4 0x5 0x6 0x7 Get Data From id: 0x242 0x0 0x1 0xD 0x3 0x4 0x5 0x6 0x7 Get Data From id: 0x743 0x0 0x1 0xF 0x3 0x4 0x5 0x6 0x7 Get Data From id: 0x242 0x0 0x1 0x10 0x3 0x4 0x5 0x6 0x7 Get Data From id: 0x743 0x0 0x1 0x12 0x3 0x4 0x5 0x6 0x7 Get Data From id: 0x242 0x0 0x1 0x13 0x3 0x4 0x5 0x6 0x7</sup> <sup>

Nachdem ich dein Sketch auf meine Hardware angepasst habe klappt es jetzt auch bei mir! :slight_smile:

Geändert:

MCP_CAN CAN(SPI_CS_PIN); // Set CS pin to 9
while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_16MHz)) // init can bus : baudrate = 500k

Muss kurz weg, schaue mir nachher mal an warum es mit meinem ersten Sketch nicht geklappt hat...

Hier das funktionierende Sketch für den UNO mit CAN-Shield V1.2

Besten Dank schon mal an alle die mitgewirkt haben!

#include <SPI.h>
#include "mcp_can.h"

// the cs pin of the version after v1.1 is default to D9
// v0.9b and v1.0 is default D10
const int SPI_CS_PIN = 9;    // CAN-Shield

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin


unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

void setup()
{
  Serial.begin(115200);

  while (CAN_OK != CAN.begin(CAN_500KBPS, MCP_16MHz))              // init can bus : baudrate = 500k
  {
    Serial.println("CAN BUS Shield init fail");
    Serial.println(" Init CAN BUS Shield again");
    delay(100);
  }
  Serial.println("CAN BUS Shield init ok!");

  attachInterrupt(0, MCP2515_ISR, FALLING); // start interrupt


  /*
     set mask, set both the mask to 0x3ff
  */
  CAN.init_Mask(0, 0, 0x7FF);                         // there are 2 mask in mcp2515, you need to set both of them
  CAN.init_Mask(1, 0, 0x7FF);

  CAN.init_Filt(0, 0, 0x2C1);                          // there are 6 filter in mcp2515
  CAN.init_Filt(1, 0, 0x668);                          // there are 6 filter in mcp2515
}

void MCP2515_ISR()
{
  flagRecv = 1;
}

void loop()
{
  //if (CAN_MSGAVAIL == CAN.checkReceive())           // check if data coming
  if(flagRecv)                   // check if get data
  {
    flagRecv = 0;                // clear flag
    CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

    Serial.print("Get Data From id: 0x");
    Serial.print(CAN.getCanId(), HEX);
    for (int i = 0; i < len; i++) // print the data
    {
      Serial.print("\t0x");
      Serial.print(buf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();

  }
}

Hi

Bei den gewählten IDs, Die gefiltert werden sollen, würde dort nicht

0x02C1
00000010 11000001
0x0668
00000110 01101000
=============
0x06E9
00000110 11101001

als Maske 0x6E9 'reichen'? Klar deckt hier 0x7FF diese beiden IDs auch ab - aber dann kann ich auch gleich 0xFFFF schreiben, wenn eh Alles durch die erste Prüfung durch kommen soll.

Wobei ich die Sache mit den Masken und den Filtern nicht wirklich verstanden habe - momentan wäre meine Vermutung, daß die empfangene ID nur gesetzte Bits haben darf, wo die Masken Bits gesetzt haben (oder weniger) UND die Bits gesetzt sein müssen, Die bei den Filtern gesetzt sind - dort aber die Filter einzeln.
... oder
(ID AND Maske_0 AND Filt_0 == Filt_0) OR (ID AND Maske_1 AND Filt_1 == Filt_1)
??

MfG
MfG

So, ich habe den "Fehler" gefunden. Es funktionieren beide Sketches, der Fehler liegt daran das ich vorher immer den Logger in einer Endlosschleife hatte, er also permanent über CAN gesendet hat (auch während des Flashens).

Der Code von agmue funktioniert auch nicht wenn ich während des Flashen des UNO schon CAN-Botschaften sende. Auch ein drücken auf die UNO Reset Taste bringt dann nichts.

Ich vermute der MCP2515 bekommt während des Inits fehlerhafte CAN-Botschaften und setzt irgendein Error Flag das eventuell erst gelöscht werden muss damit er wieder normal funktioniert.

Habe gerade noch getestet, der Fehler tritt auch auf wenn man den UNO resettet und vorher nicht das Senden der CAN-Botschaften unterbricht.

Gibt es da noch Error Flags die erst gelöscht werden müssen?

Habe noch raus gefunden das wenn der Fehler da ist der Befehl CAN.checkError eine 5 liefert (im Normalfall 0)

postmaster-ino:
Bei den gewählten IDs, Die gefiltert werden sollen, würde dort nicht ...
als Maske 0x6E9 'reichen'? Klar deckt hier 0x7FF diese beiden IDs auch ab - aber dann kann ich auch gleich 0xFFFF schreiben, wenn eh Alles durch die erste Prüfung durch kommen soll.

Wenn Du Dir im Datenblatt die Tabelle "STANDARD DATA FRAME" ansiehst, hat der Identifier nur 11 Bits, was den maximalen Wert 0x7FF begründet.

In der Tabelle "FILTER/MASK TRUTH TABLE" erkennt man die zugrunde liegende Logik. Über die Akzeptanz-Maske wird die Relavanz eines Bits festgelegt.

Jackson0:
Der Code von agmue funktioniert auch nicht wenn ich während des Flashen des UNO schon CAN-Botschaften sende.

Das habe ich so noch nicht beobachtet, allerdings sende ich immer nur jede Sekunde und verwende andere Hardware.

In der Bibliothek gibt es mcp2515_reset "reset the device". Ob der Reset des Arduinos mit dem Reset des MCP2515 auf dem Shield verbunden ist, mußt Du mal bei Dir schauen.

Mit dem Software Reset CAN.mcp2515_reset(); habe ich versucht, aber gibt immer diese Fehlermeldung:

C:\Users\Jackson\Documents\Arduino\libraries\CAN_BUS_Shield-master/mcp_can.h: In function 'void loop()':

C:\Users\Jackson\Documents\Arduino\libraries\CAN_BUS_Shield-master/mcp_can.h:73:10: error: 'void MCP_CAN::mcp2515_reset()' is private

     void mcp2515_reset(void);                                   // reset mcp2515

          ^

CAN:144:50: error: within this context

       if ( CAN.checkError() )  CAN.mcp2515_reset();

                                                  ^

exit status 1
within this context

Das Empfangen bestimmter ID-Thema ist erfolgreich abgeschlossen.

Habe zum Thema CAN.checkError ein neues Thema eröffnet...

Jackson0:
Das Empfangen bestimmter ID-Thema ist erfolgreich abgeschlossen.

Freut mich, danke für die Rückmeldung :slight_smile:

Wenn Du es ganz gut machen möchtest, editierst Du Beitrag #0 und änderst den Titel in "[gelöst] Arduino CAN-Shield Interrupt nur bei bestimmter CAN-ID" oder was Dir so einfällt.