CAN-BUS Shield

简介

CAN-BUS Shield V2.0是专为Arduino控制器设计的扩展板,板载MCP2515总线控制芯片能够实现CAN总线上的数据控制,实现设备与设备之间的数据通信。扩展板兼容Arduino标准卡槽,可以完美适配于Arduino UNO,Leonardo等主控板。并且提供一个DB9和一个接线柱形式的接口,您可以根据需要自主选择接口。内嵌MicroSD卡槽,可直插MicroSD卡,存储数据。多种扩展接口使得用户在DIY过程中得到更大的便利。

特性

参数

接口说明

Can-bus接口说明图.jpg

两种供电方式:

Power Switch 处于“ON”端,电源由DB9接口的供电

Power Switch 处于“OFF”端,电源由Arduino主板供应

注意:

当DP9接口处的电压大于7V时可以为arduino主控板供电,开关选择”ON“;

如果arduino主板是usb供电,那么USB和DB9可以同时供电;如果arduino是DC-Vin电源供电,DB9就不能同时供电了,必须将开关置于”OFF“处 |

CAN-BUS节点配置

本节内容主要介绍如何用我们提供的函数库去DIY您的创意或者说您的产品。为了能够表述的容易理解,我们决定从最基础的知识开始介绍,然后结合一个例子进一步阐述。 1、can-bus节点(设备) 什么叫做can-bus节点呢? 首先我们要明确的一点就是can-bus是一个局域网控制协议。既然是局域网,那么该网络上一定有很多设备相连的。每个设备就是一个节点,而每个节点上有一个can-bus协议控制器(控制芯片)。

2、can-bus总线上的节点即可以作为接收器,又可以作为发射器,即一般来地,我们称can-bus的节点为收发器。

3、can-bus总线上没有地址的概念,所有can-bus的数据帧都是被id所区分,每个设备对应一个id。 假如A节点发送id为0x1123的标准数据帧,D节点也可以发送id为0x1123的标准数据帧。当然实际工程中很少这样,一般来说,不同的id对应不同的收发器,不同的收发器完成不同的功能;又或者相同的收发器发送不同的id,不同的id发送不同需求的数据。

4、can-bus节点依靠自身的硬件屏蔽功能,实现选择性的接受来自在初始化时指定id的数据帧。 可以通过调用init_Mask(Masker_t Masker_num, INT8U ext, INT32U ulData)init_Filter(Filter_t Filter_num, INT8U ext, INT32U Data)配置选择性接受指定的id。参见Arduino库函数功能说明

5、can-bus总线上的任意一个节点发送的数据都可以被其他节点选择性的接受。该节点也可以选择性的接收其他节点发送的数据。

结合以上5点分析can-bus总线上的数据传输情况: 举例来说,假如在一个由五个节点的局域网中,节点名称分别是:A、B、C、D、E。其中B节点只可以接收id为0x06的标准数据帧,那么当节点A要向节点B发送数据“hello world”,那么可以调用我们的sendMsgBuf(0x06, 0, 12, "hello world")函数即可。此时这五个节点组成的局域网的总线(H线和L线)上,传输的就是包括“hello world”数据在内的标准数据帧,且该数据帧的id为0x06,那么节点B就可以接受到该数据帧了。

那么其他节点可以接受该数据帧吗?答案是可以的,只要你设定的id与发送时指定的id相符合,既可以接受数据,例如: 假设:

  1. 节点B的数据帧接收id:0x06
  2. 节点C的数据帧接收id:0x06和0x08
  3. 节点D的数据帧接收id:0x07
  4. 节点E的数据帧接收id:任意

那么:

  1. 当节点A发送id为0x06的标准数据帧时,那么可接收到的节点是B、C、E;
  2. 当节点A发送id为0x07的标准数据帧时,那么可接收到的节点是D、E;
  3. 当节点A发送id为0x08的标准数据帧时,那么可接收到的节点是C、E;
  4. 当节点A发送id为0x12的标准数据帧时,那么可接收到的节点是E;

Arduino库函数功能说明

MCPCAN(INT8U _CS) 函数功能: 构造函数,指定CAN-BUS Shield V1.0模块的CAN接口SPI的片选信号引脚。 参数说明:

返回值:无。 使用方法:

MCPCAN CAN(4); // 用MCPCAN类实例化了一个CAN对象,可以用该对象调用该类的方法去控制can控制器。_CS 此处为4,表明arduino的数字管脚4作为spi的cs脚与can总线控制器相连接。


void init(void) 函数功能: 初始化spi模块,以及对MCP2515进行软件复位。 参数说明: 无 返回值:无。 使用方法:

该函数应该在一开始就调用,以初始化can总线控制器等。


INT8U begin(INT8U speedset) 函数功能: 初始化设置CAN的波特率,在init()后面使用。 参数说明:

返回值:如果初始化成功返回CAN_OK,如果初始化失败返回CAN_FAILINIT。 使用方法:

begin(CAN_500KBPS);


INT8U sendMsgBuf(INT32U id, INT8U ext, INT8U len, INT8U *buf) 函数功能:发送一帧数据。 参数说明:

返回值:如果发送成功,则返回CAN_OK,如果发送超时,则返回CAN_SENDMSGTIMEOUT。如果获取下一个空闲buffer失败,则返回CAN_GETTXBFTIMEOUT。 使用方法:

   unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
   sendMsgBuf(0x06, 0, sizeof(data), data); 

INT8U MCPCAN::setMsg(INT32U id, INT8U ext, INT8U len, INT8U rtr, INT8U *pData) 函数功能:发送远程发送请求报文。 参数说明:

返回值:如果发送成功,则返回CAN_OK,如果发送超时,则返回CAN_SENDMSGTIMEOUT。如果获取下一个空闲buffer失败,则返回CAN_GETTXBFTIMEOUT。 使用方法:

   unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
   setMsg(0x06, 0, sizeof(data), 0, data);

INT8U isRemoteRequest(void) 函数功能:判断是否是远程遥控帧。 参考说明 无 返回值:如果返回1,表示该数据帧是远程遥控帧,如果返回0,则表示不是远程遥控帧。


INT8U init_Mask(Masker_t Masker_num, INT8U ext, INT32U Data) 函数功能:初始化屏蔽寄存器。 参数说明:

返回值:如果Masker_num即不是MCP_RXM0也不是MCP_RXM1或者初始化屏蔽寄存器失败,则返回MCP_FAIL;如果初始化屏蔽寄存器成功则返回MCP_OK; 使用方法:

init_Mask(MCP_RXM0, 0, 0x3ff); //在init()函数之后使用,begin()之前。期望对标准帧的0~9位进行过滤共10位,因为0x3ff的二进制形式是11 1111 1111,这里刚好10位。


INT8U checkReceive(void) 函数功能:检测是否接收到有效的数据帧。 参数说明: 无 返回值:如果接收到有效的数据帧,则返回CAN_MSGAVAIL;如果没有接收到有效的数据帧,则返回CAN_NOMSG; 使用方法:

在can总线控制器工作起来后,可以轮训调用该函数来检测是否接收到有效的数据帧,请参见下面样例。


INT8U init_Filter(Filter_t Filter_num, INT8U ext, INT32U Data) 函数功能:初始化报文验收滤波寄存器。 参数说明:

Can-4.2.png

返回值:如果初始化成功,则返回MCP_OK;反之,返回MCP_FA

使用方法:

     init_Mask(MCP_RXM0, 0, 0x7ff);
     init_Filter(MCP_RXF0, 0, 0x04);//在init()函数之后,begin()之前使用,且和init_Mask()共同起作用。设置can控制器对标准帧id 0x04进行接收。

INT8U readMsgBuf(INT8U *len, INT8U *buf) 函数功能:从MCP2515接收buffer中读取数据。 参数说明:

返回值:如果返回CAN_OK,则表示读取数据成功;反之返回CAN_NOMSG。 使用方法:

在can总线工作起来后,如果有数据帧到来调用该函数可以把该数据帧读出来,参见后续章节样例。


INT8U readMsgBufID(INT32U *ID, INT8U *len, INT8U *buf) 函数功能:从MCP2515接收buffer中读取数据,并读取此帧数据的id。 参数说明:

返回值:如果返回CAN_OK,则表示读取数据成功;反之返回CAN_NOMSG。 使用方式:

用法同readMsgBuf()函数类似只是多了一个ID用于返回该帧数据的ID号。


INT8U checkError(void) 函数功能:检测MCP2515是否发送控制错误。 参数说明: 无。 返回值:如果发送了控制错误,则返回CAN_CTRLERROR;反之返回CAN_OK。


INT32U getCanId(void) 函数说明:获取当前帧的id。 参数说明: 无。 返回值:帧id。

当接收到数据后,调用此函数用于得到接收到的数据帧的ID,参见后续章节样例。


INT8U isExtendedFrame(void) 函数说明:判断当前帧是否为扩展帧。 参数说明: 无 返回值:如果返回1,则表示当前帧为扩展帧;如果返回0,则表示当前帧是标准帧。

在接收中断处理函数中调用,以判断数据帧是标准数据帧还是扩展帧。


实验教程

准备

基本的CAN收发功能(轮询接收)

本实验测试基本的CAN收发功能,其中接收采用轮询方式,可以接受任意id的标准数据帧或扩展帧。发射节点每隔100ms发送一帧id为0x06的标准数据帧。

实验接线

CAN-BUS Shield V2.0模块组网时,模块间连线为:CANH与CANH相连接,CANL与CANL相连接,如下图:

DFR0370-TWO.png

例程代码

接收端点例程

    /******************************************************************************
    * demo: CAN-BUS Shield, receive data with check mode
    * send data coming to fast, such as less than 10ms, you can use this way
    * Jansion, 2015.5.27
    ******************************************************************************/
    #include <SPI.h>
    #include "df_can.h"
    const int SPI_CS_PIN = 10;
    MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin
    void setup()
    {
          Serial.begin(115200);
          int count = 50;                                     // the max numbers of initializint the CAN-BUS, if initialize failed first!.
          do {
              CAN.init();   //must initialize the Can interface here!
              if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
              {
                  Serial.println("DFROBOT's CAN BUS Shield init ok!");
                  break;
              }
              else
              {
                  Serial.println("DFROBOT's CAN BUS Shield init fail");
                  Serial.println("Please Init CAN BUS Shield again");

                  delay(100);
                  if (count <= 1)
                      Serial.println("Please give up trying!, trying is useless!");
              }

          }while(count--);

    }
    void loop()
    {
          unsigned char len = 0;
          unsigned char buf[8];

          if(CAN_MSGAVAIL == CAN.checkReceive())            // check if data coming
          {
              CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

              for(int i = 0; i<len; i++)    // print the data
              {
                  Serial.write(buf[i]);
                  Serial.print("\t");
              }
              Serial.println();
          }
    }
发射端点例程
  // demo: CAN-BUS Shield, send data
  #include <df_can.h>
  #include <SPI.h>

  const int SPI_CS_PIN = 10;

  MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin

  void setup()
  {
      Serial.begin(115200);
      int count = 50;                   // the max numbers of initializint the CAN-BUS, if initialize failed first!.
      do {
          CAN.init();   //must initialize the Can interface here!
          if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
          {
              Serial.println("DFROBOT's CAN BUS Shield init ok!");
              break;
          }
          else
          {
              Serial.println("DFROBOT's CAN BUS Shield init fail");
              Serial.println("Please Init CAN BUS Shield again");

              delay(100);
              if (count <= 1)
                  Serial.println("Please give up trying!, trying is useless!");
          }

      }while(count--);

}

unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
void loop()
  {
      // send data:  id = 0x06, standrad flame, data len = 8, data: data buf
      CAN.sendMsgBuf(0x06, 0, 8, data);
      delay(100);                       // send data per 100ms
  }

实验现象

接收方:串口输出:

Blune M3

基本收发功能(中断接收)

本实验测试基本收发功能,接收采用中断方式。

实验接线

DFR0370-TWO.png

例程代码

接收端点例程

    /***********************************************************
      *demo: CAN-BUS Shield, receive data with interrupt mode
      * when in interrupt mode, the data coming can't be too fast, must >20ms, or else you can use check mode
      * Jansion, 2015-5-27
    ***********************************************************/
      #include <SPI.h>
      #include "df_can.h"

      const int SPI_CS_PIN = 10;
      MCPCAN 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);
          int count = 50;   // the max numbers of initializint the CAN-BUS, if initialize failed first!.
          do {
              CAN.init();   //must initialize the Can interface here!
              if(CAN_OK == CAN.begin(CAN_500KBPS))    // init can bus : baudrate = 500k
              {
                  Serial.println("DFROBOT's CAN BUS Shield init ok!");
                  break;
              }
              else
              {
                  Serial.println("DFROBOT's CAN BUS Shield init fail");
                  Serial.println("Please Init CAN BUS Shield again");

                  delay(100);
                  if (count <= 1)
                      Serial.println("Please give up trying!, trying is useless!");
              }

          }while(count--);


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

      void MCP2515_ISR()
      {
          flagRecv = 1;
      }

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

              flagRecv = 0;                   // clear flag

              // iterate over all pending messages
              // If either the bus is saturated or the MCU is busy,
              // both RX buffers may be in use and after having read a single
              // message, MCU does  clear the corresponding IRQ conditon.
              while (CAN_MSGAVAIL == CAN.checkReceive())
              {
                  // read data,  len: data length, buf: data buf
                  CAN.readMsgBuf(&len, buf);

                  // print the data
                  for(int i = 0; i<len; i++)
                  {
                      Serial.write(buf[i]);Serial.print("\t");
                  }
                  Serial.println();
              }
          }
      }

发射端点例程
  // demo: CAN-BUS Shield, send data
  #include <df_can.h>
  #include <SPI.h>

  const int SPI_CS_PIN = 10;

  MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin

  void setup()
  {
      Serial.begin(115200);
      int count = 50;      // the max numbers of initializint the CAN-BUS, if initialize failed first!.
      do {
          CAN.init();   //must initialize the Can interface here!
          if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
          {
              Serial.println("DFROBOT's CAN BUS Shield init ok!");
              break;
          }
          else
          {
              Serial.println("DFROBOT's CAN BUS Shield init fail");
              Serial.println("Please Init CAN BUS Shield again");

              delay(100);
              if (count <= 1)
                  Serial.println("Please give up trying!, trying is useless!");
          }

      }while(count--);

  }

  unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
  void loop()
  {
      // send data:  id = 0x06, standrad flame, data len = 8, data: data buf
      CAN.sendMsgBuf(0x06, 0, 8, data);
      delay(100);                       // send data per 100ms
  }

实验现象

接收方:串口中输出:

Blune M3

接受指定ID数据帧(中断接收)

本实验测试只接受初始化CAN模块时指定id的数据帧,接收采用中断方式。

实验接线

DFR0370-TWO.png

例程代码

接收端点例程

    /**************************************************************************************************************
       *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
       * Jansion, 2015-5-27
     ****************************************************************************************************************/
      #include <SPI.h>
      #include "df_can.h"
      const int SPI_CS_PIN = 10;
      MCPCAN 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);
          int count = 50;   // the max numbers of initializint the CAN-BUS, if initialize failed first!.

          do {
              CAN.init();   //must initialize the Can interface here!
        CAN.init_Mask(MCP_RXM0, 0, 0x3ff);// there are 2 mask in mcp2515, you need to set both of them
              CAN.init_Mask(MCP_RXM1, 0, 0x3ff);
              /*
               * set filter, we can receive id from 0x04 ~ 0x09 except for 0x06
               * // there are 6 filter in mcp2515,so it can filter six id,i.e.0x04~0x09.
               */
              CAN.init_Filter(MCP_RXF0, 0, 0x04);                         // filter 0 for id = 0x04
              CAN.init_Filter(MCP_RXF1, 0, 0x05);                         // filter 1 for id = 0x05
              // CAN.init_Filter(MCP_RXF2, 0, 0x06);                         // filter 2 for id = 0x06
              CAN.init_Filter(MCP_RXF3, 0, 0x07);                         // filter 3 for id = 0x07
              CAN.init_Filter(MCP_RXF4, 0, 0x08);                         // filter 4 for id = 0x08
              CAN.init_Filter(MCP_RXF5, 0, 0x09);                         // filter 5 for id = 0x09
              if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
              {
                  Serial.println("DFROBOT's CAN BUS Shield init ok!");
                  break;
              }
              else
              {
                  Serial.println("DFROBOT's CAN BUS Shield init fail");
                  Serial.println("Please Init CAN BUS Shield again");

                  delay(100);
                  if (count <= 1)
                      Serial.println("Please give up trying!, trying is useless!");
              }

          }while(count--);

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


          /*
           * set mask, set both the mask to 0x3ff
           */

      }

      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();

          }
      }
发射端点例程
  /***************************************************************
  * demo: set_mask_filter_send
  * this demo will show you how to use mask and filter
  * Jansion, 2015-5-27
  *****************************************************************/
  #include <df_can.h>
  #include <SPI.h>
  const int SPI_CS_PIN = 10;
  MCPCAN CAN(SPI_CS_PIN);                                   // Set CS pin
  void setup()
  {
      Serial.begin(115200);
      int count = 50; // the max numbers of initializint the CAN-BUS, if initialize failed first!.
      do {
          CAN.init();   //must initialize the Can interface here!
          if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
          {
              Serial.println("DFROBOT's CAN BUS Shield init ok!");
              break;
          }
          else
          {
              Serial.println("DFROBOT's CAN BUS Shield init fail");
              Serial.println("Please Init CAN BUS Shield again");

              delay(100);
              if (count <= 1)
                  Serial.println("Please give up trying!, trying is useless!");
          }

      }while(count--);
  }

  unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};

  void loop()
  {
      for(int id=0; id<10; id++)
      {
          memset(data, id, sizeof(data));  // set id to send data buff, id is arranged form 0x00 to 0x09.
          CAN.sendMsgBuf(id, 0, sizeof(data), data);
          delay(100);
      }
  }

实验现象

接收方:串口输出:

CAN-BUS Shield V2.0

注意:接收到的数据帧中既没有没有id号为0x06的报文,也没有id为0x00,0x01,0x02等与报文验收滤波器设置的id不匹配的其他报文。这说明,滤波器可以单个工作,或者几个滤波器同时工作,又或者全部滤波器同时工作。当不使用时,可接受任意报文。

三模块组网

本实验测试三个模块组网,数据的收发情况。三个模块中每个模块既可以作为接收者,也可以作为发送者。本实验中3个节点设备,分别为称为node 1,node 2, node 3。其中node 1只作为接收节点,可以接收id为0x04,0x05,0x07,0x08,0x09的数据帧;node 2只接收id 为0x09的数据帧和发送id为0x08且数据为”node 2“的数据帧;node 3只接收id 为0x08的数据帧和发送id为0x09且数据为”node 3“的数据帧;

实验接线

3个CAN-BUS Shield V2.0模块组网时,模块间连线为:CANH与CANH相连接,CANL与CANL相连接,如下图:

DFR0370-THREE.png

例程代码

Node 1例程

    /**************************************************************************************************************
      *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
      * Jansion, 2015-5-27
    ****************************************************************************************************************/
      #include <SPI.h>
      #include "df_can.h"

      const int SPI_CS_PIN = 10;
      MCPCAN 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);
          int count = 50;                                     // the max numbers of initializint the CAN-BUS, if initialize failed first!.

          do {
              CAN.init();   //must initialize the Can interface here!
              CAN.init_Mask(MCP_RXM0, 0, 0x3ff);                         // there are 2 mask in mcp2515, you need to set both of them
              CAN.init_Mask(MCP_RXM1, 0, 0x3ff);
              /*
               * set filter, we can receive id from 0x04 ~ 0x09 except for 0x06
               * // there are 6 filter in mcp2515,so it can filter six id,i.e.0x04~0x09.
               */
              CAN.init_Filter(MCP_RXF0, 0, 0x04);                         // filter 0 for id = 0x04
              CAN.init_Filter(MCP_RXF1, 0, 0x05);                         // filter 1 for id = 0x05
              // CAN.init_Filter(MCP_RXF2, 0, 0x06);                         // filter 2 for id = 0x06
              CAN.init_Filter(MCP_RXF3, 0, 0x07);                         // filter 3 for id = 0x07
              CAN.init_Filter(MCP_RXF4, 0, 0x08);                         // filter 4 for id = 0x08
              CAN.init_Filter(MCP_RXF5, 0, 0x09);                         // filter 5 for id = 0x09
              if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
              {
                  Serial.println("DFROBOT's CAN BUS Shield init ok!");
                  break;
              }
              else
              {
                  Serial.println("DFROBOT's CAN BUS Shield init fail");
                  Serial.println("Please Init CAN BUS Shield again");

                  delay(100);
                  if (count <= 1)
                      Serial.println("Please give up trying!, trying is useless!");
              }

          }while(count--);

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


          /*
           * set mask, set both the mask to 0x3ff
           */

      }

      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.write(buf[i]);
                 Serial.print("\t");
              }
              Serial.println();

          }
      }

Node 2例程
   #include <SPI.h>
   #include "df_can.h"

   const int SPI_CS_PIN = 10;
   MCPCAN 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);
     int count = 50;   // the max numbers of initializint the CAN-BUS, if initialize failed first!.

     do {
         CAN.init();   //must initialize the Can interface here!
         CAN.init_Mask(MCP_RXM0, 0, 0x3ff);  // there are 2 mask in mcp2515, you need to set both of them
         CAN.init_Mask(MCP_RXM1, 0, 0x3ff);
         /*
          * set filter, we can receive id from 0x04 ~ 0x09 except for 0x06
          * // there are 6 filter in mcp2515,so it can filter six id,i.e.0x04~0x09.
          */
         CAN.init_Filter(MCP_RXF5, 0, 0x09);                         // filter 5 for id = 0x09
         if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
         {
             Serial.println("DFROBOT's CAN BUS Shield init ok!");
             break;
         }
         else
         {
             Serial.println("DFROBOT's CAN BUS Shield init fail");
             Serial.println("Please Init CAN BUS Shield again");

             delay(100);
             if (count <= 1)
                 Serial.println("Please give up trying!, trying is useless!");
         }

     }while(count--);

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


     /*
      * set mask, set both the mask to 0x3ff
      */

   }

   void MCP2515_ISR()
   {
     flagRecv = 1;
   }


   unsigned char data[] = "node 2";
   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.write(buf[i]);
             Serial.print("\t");
         }
         Serial.println();
     }

     // send data:  id = 0x08, standrad flame, data len = 8, data: data buf
     CAN.sendMsgBuf(0x08, 0, sizeof(data), data);
     delay(1000);                       // send data per 100ms

   }
Node 3例程
   #include <SPI.h>
   #include "df_can.h"

   const int SPI_CS_PIN = 10;
   MCPCAN 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);
     int count = 50; // the max numbers of initializint the CAN-BUS, if initialize failed first!.

     do {
         CAN.init();   //must initialize the Can interface here!
         CAN.init_Mask(MCP_RXM0, 0, 0x3ff); // there are 2 mask in mcp2515, you need to set both of them
         CAN.init_Mask(MCP_RXM1, 0, 0x3ff);
         /*
          * set filter, we can receive id from 0x04 ~ 0x09 except for 0x06
          * // there are 6 filter in mcp2515,so it can filter six id,i.e.0x04~0x09.
          */
         CAN.init_Filter(MCP_RXF5, 0, 0x08);                         // filter 5 for id = 0x09
         if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
         {
             Serial.println("DFROBOT's CAN BUS Shield init ok!");
             break;
         }
         else
         {
             Serial.println("DFROBOT's CAN BUS Shield init fail");
             Serial.println("Please Init CAN BUS Shield again");

             delay(100);
             if (count <= 1)
                 Serial.println("Please give up trying!, trying is useless!");
         }

     }while(count--);

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


     /*
      * set mask, set both the mask to 0x3ff
      */

   }

   void MCP2515_ISR()
   {
     flagRecv = 1;
   }


   unsigned char data[] = "node 3";
   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.write(buf[i]);
             Serial.print("\t");
         }
         Serial.println();
     }

     // send data:  id = 0x08, standrad flame, data len = 8, data: data buf
     CAN.sendMsgBuf(0x09, 0, sizeof(data), data);
     delay(1000);                       // send data per 100ms

   }

实验现象

CAN接收方串口不断输出下图信息:

CAN-BUS Shield V2.0

实验现象分析: COM21烧写的是Node 1例程代码,它接收到了id为0x09和id为0x08的数据帧。COM10是Node 3的串口输出,Node 3既可以接收id为0x08的数据帧也可以发送id为0x09的数据帧。COM12是Node 2的串口输出,Node 2既可以接收id为0x09的数据帧也可以发送id为0x08的数据帧。

SD卡存取

本实验的目的是:接收节点接收十条发送节点传来的数据,然后将其出入到CAN-BUS Shield sd卡中。最后将其读出并通过串口打印出来。

实验接线

把SD卡插入到can-bus扩展板上,模块间连线为:CANH与CANH相连接,CANL与CANL相连接,如下图:

DFR0370-TWO.png

例程代码

发送节点例程
 // demo: CAN-BUS Shield, send data
  #include <df_can.h>
  #include <SPI.h>

  const int SPI_CS_PIN = 10;

  MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin

  void setup()
  {
      Serial.begin(115200);
      int count = 50; // the max numbers of initializint the CAN-BUS, if initialize failed first!.
      do {
          CAN.init();   //must initialize the Can interface here!
          if(CAN_OK == CAN.begin(CAN_500KBPS))     // init can bus : baudrate = 500k
          {
              Serial.println("DFROBOT's CAN BUS Shield init ok!");
              break;
          }
          else
          {
              Serial.println("DFROBOT's CAN BUS Shield init fail");
              Serial.println("Please Init CAN BUS Shield again");

              delay(100);
              if (count <= 1)
                  Serial.println("Please give up trying!, trying is useless!");
          }

      }while(count--);

  }

  unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
  void loop()
  {
      // send data:  id = 0x60, standrad flame, data len = 8, data: data buf
      CAN.sendMsgBuf(0x60, 0, 8, data);
      delay(1000);                       // send data per 100ms
  }
接收节点例程
 /**************************************************************************************************************
 *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
 * Jansion, 2015-5-27
 ****************************************************************************************************************/
#include <SPI.h>
#include "df_can.h"
#include <SD.h>

const int SPI_CS_PIN = 10;
MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin
unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];
char  sd_cspin = 4; //pin 4 as spi_cs pin
File myFile;

void setup()
{
    Serial.begin(115200);
    int count = 50; // the max numbers of initializint the CAN-BUS, if initialize failed first!.
    Serial.print("Initializing can controlor...");
    do {
        CAN.init();   //must initialize the Can interface here!
        CAN.init_Mask(MCP_RXM0, 0, 0x3ff);  // there are 2 mask in mcp2515, you need to set both of them
        CAN.init_Mask(MCP_RXM1, 0, 0x3ff);
        /*
         * set filter, we can receive id from 0x04, 0x05, 0x60, 0x07, 0x08, 0x09
         *
         */
        CAN.init_Filter(MCP_RXF0, 0, 0x04);                         // filter 0 for id = 0x04
        CAN.init_Filter(MCP_RXF1, 0, 0x05);                         // filter 1 for id = 0x05
        CAN.init_Filter(MCP_RXF2, 0, 0x60);                         // filter 2 for id = 0x60
        CAN.init_Filter(MCP_RXF3, 0, 0x07);                         // filter 3 for id = 0x07
        CAN.init_Filter(MCP_RXF4, 0, 0x08);                         // filter 4 for id = 0x08
        CAN.init_Filter(MCP_RXF5, 0, 0x09);                         // filter 5 for id = 0x09
        if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
        {
            Serial.println("DFROBOT's CAN BUS Shield init ok!");
            break;
        }
        else
        {
            Serial.println("DFROBOT's CAN BUS Shield init fail");
            Serial.println("Please Init CAN BUS Shield again");

            delay(100);
            if (count <= 1)
                Serial.println("Please give up trying!, trying is useless!");
        }

    }while(count--);

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

    Serial.print("Initializing SD card...");

    if (!SD.begin(sd_cspin)) {
        Serial.println("initialization failed!");
        return;
    }
    Serial.println("initialization success!");
    myFile = SD.open("Node0x60.txt", FILE_WRITE); //the file named Node0x60.txt use to save the data
    // with the frame id equeling 0x60.
    if (!myFile)
    {
        Serial.println("open Node0x60.text failed!");


    }
    else
    {
        Serial.println("open Node0x60.text success!");
    }
    /*
     * set mask, set both the mask to 0x3ff
     */

}

void MCP2515_ISR()
{
    flagRecv = 1;
}
char filewrite = 1, fileread = 0;
int i = 0, j = 0;
void loop()
{

    if(flagRecv)                   // check if get data
    {
        flagRecv = 0;                // clear flag
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf
        if (filewrite)
        {
            if (i++ < 1) //only recieve one frame
            {
                myFile.write(buf, len);
            }
            else
            {
                myFile.close();
                filewrite = 0;
                myFile = SD.open("Node0x60.txt", FILE_WRITE);
                if (SD.exists("Node0x60.txt")) {
                    Serial.println("example.txt exists.");
                    fileread = 1;
                }
                else {
                    Serial.println("example.txt doesn't exist.");
                }
            }
        }
        if (fileread)
        {
            Serial.println("printf the data that myFile has saved! ");
            myFile.read(buf, len);
            Serial.println((char *)buf);
            Serial.println("");
            myFile.close();

            Serial.println("myFile closed!!!!");
            fileread = 0;
        }

    }

实验现象

接收方:串口输出:

CAN-BUS Shield V2.0

实验现象分析:接收节点接收到id为0x60的数据帧,并将其存入到文件名为Node0x60.text文件中,然后关闭文件。最后又打开文件,并从文件中读出刚才收到的数据通过串口打印出来,如上图所示。

协议/库资料

CAN总线百度百科

常见问题

还没有客户对此产品有任何问题,欢迎通过qq或者论坛联系我们!

更多问题及有趣的应用,可以 访问论坛 进行查阅或发帖!

更多

MCP2515 datasheet 原理图 Arduino library SVG文件

DFshopping_car1.png DFRobot商城购买链接