1.产品简介
CAN-BUS Shield V2.0是专为Arduino控制器设计的扩展板,板载MCP2515总线控制芯片能够实现CAN总线上的数据控制,实现设备与设备之间的数据通信。扩展板兼容Arduino标准卡槽,可以完美适配于Arduino UNO,Leonardo等主控板。并且提供一个DB9和一个接线柱形式的接口,您可以根据需要自主选择接口。内嵌MicroSD卡槽,可直插MicroSD卡,存储数据。多种扩展接口使得用户在DIY过程中得到更大的便利。
2.产品特性
- 支持标准帧、扩展帧收发,支持轮训和中断
- 提供UART、I2C、DB9及接线柱等多种接口
- 支持SD卡数据存储
- 支持Arduino主板供电以及DB9接口供电
3.产品参数
- 芯片:MCP2515
- 供电:3.3~5VDC Arduino 主板供电/DB9接口供电
- 尺寸:76 mm * 54mm *19mm
- 重量:40g
4.接口说明
两种供电方式:
Power Switch 处于“ON”端,电源由DB9接口的供电
Power Switch 处于“OFF”端,电源由Arduino主板供应
注意:
当DP9接口处的电压大于7V时可以为arduino主控板供电,开关选择”ON“;
如果arduino主板是usb供电,那么USB和DB9可以同时供电;如果arduino是DC-Vin电源供电,DB9就不能同时供电了,必须将开关置于”OFF“处
5.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相符合,既可以接受数据,例如: 假设:
- 节点B的数据帧接收id:0x06
- 节点C的数据帧接收id:0x06和0x08
- 节点D的数据帧接收id:0x07
- 节点E的数据帧接收id:任意
那么:
- 当节点A发送id为0x06的标准数据帧时,那么可接收到的节点是B、C、E;
- 当节点A发送id为0x07的标准数据帧时,那么可接收到的节点是D、E;
- 当节点A发送id为0x08的标准数据帧时,那么可接收到的节点是C、E;
- 当节点A发送id为0x12的标准数据帧时,那么可接收到的节点是E;
6.Arduino库函数功能说明
DFRobot_MCP2515(uint8_t csPin)**
函数功能: 构造函数,指定CAN-BUS Shield V2.0模块的CAN接口SPI的片选信号引脚。
参数说明:
- CS:端口编号。
返回值:无。
使用方法:单片机与can控制器MCP2515通信时的spi选择引脚
uint8_t begin(uint8_t speedset)
函数功能: 初始化设置CAN的波特率,在init()后面使用。
参数说明:
- speedset:波特率,可以是:CAN_5KBPS、CAN_10KBPS、CAN_20KBPS、CAN_31K25BPS、CAN_33KBPS、CAN_40KBPS、CAN_50KBPS、CAN_80KBPS、CAN_83K3BPS、CAN_95KBPS、CAN_100KBPS、CAN_125KBPS、CAN_200KBPS、CAN_250KBPS、CAN_500KBPS、CAN_1000KBPS。
返回值:如果初始化成功返回CAN_OK,如果初始化失败返回CAN_FAILINIT。
使用方法:begin(CAN_500KBPS);
uint8_t sendMsgBuf(uint32_t id, uint8_t ext, uint8_t len, uint8_t *buf)
函数功能:发送一帧数据。
参数说明:
- id:该数据帧消息的id编号。
- ext:如果ext = 0,则表示该数据帧是标准的数据帧,如果ext = 1,则表示该数据帧是扩展数据帧。
- len:要发送数据的长度,len < 8。
- buf:将要发送的数据缓存指针。
返回值:数据发送状态。如果成功,返回MCP2515_OK。
使用方法:
unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'}; sendMsgBuf(0x06, 0, sizeof(data), data);
uint8_t isRemoteRequest(void)
函数功能:判断是否是远程遥控帧。
参考说明 :无。
返回值:如果返回1,表示该数据帧是远程遥控帧,如果返回0,则表示不是远程遥控帧。
uint8_t initMask(eMasker_t maskerNum, uint8_t ext, uint32_t ulData)
函数功能:初始化屏蔽寄存器。
参数说明:
- Masker_num: Masker_num 可以为:MCP_RXM0、MCP_RXM1。若Masker_num = MCP_RXM0 ,表示初始化屏蔽寄存器0(屏蔽寄存器0是接收buffer0的);若Masker_num = MCP_RXM1,表示初始化屏蔽寄存器1(屏蔽寄存器1是接收buffer1的)
- ext: 如果ext = 0,表示对标准数据帧进行屏蔽寄存器设置,如果ext=1,表示对扩展帧进行配置。
- 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位。
uint8_t checkReceive(void)
函数功能:检测是否接收到有效的数据帧。
参数说明: 无
返回值:如果接收到有效的数据帧,则返回CAN_MSGAVAIL;如果没有接收到有效的数据帧,则返回CAN_NOMSG;
使用方法:在can总线控制器工作起来后,可以轮训调用该函数来检测是否接收到有效的数据帧,请参见下面样例。
uint8_t initFilter(eFilter_t filterNum, uint8_t ext, uint32_t Data)
函数功能:初始化报文验收滤波寄存器。
参数说明:
- Filter_num: 报文验证滤波器编号。Filter_num取值可以为:MCP_RXF0、 MCP_RXF1、 MCP_RXF2、 MCP_RXF3、 MCP_RXF4、 MCP_RXF5。
- ext:如果ext = 0,则表示该报文验收滤波器只验收标准数据帧报文,如果ext = 1,则表示该报文验收滤波器只验收扩展数据帧报文。
- Data:将被过滤的报文id。只有能被过滤的id的数据帧才能被can控制器接收。因此一个即将到来的数据帧能否被接收到,取决与init_Mask()函数中对MCP_RXM0,MCP_RXM1寄存器所写的值、init_Filter()函数对MCP_RXF0等寄存器所写的值以及即将到来的报文标识符ID。这三者的值按位查看表4-2的真值表。如果每一位的真值结果全为接收,那么该报文将被can控制器接收,否则将被其丢弃。比如说init_Mask(MCP_RXM0, 0, 0x7ff)函数把MCP_RXM0寄存器配置为0x7ff,表示将要对标准帧ID的11个位进行屏蔽功能。且此时init_Filter (MCP_RXF0, 0, 0x20)函数把MCP_RXF0寄存器配置为0x20,将0x20(000 0010 0000对应表4.2中的过滤位)与0x7ff(111 1111 1111 对应表4.2中的屏蔽位)中每一位按照表4.2中的真值表来决定是否接受,如果每一位的对应的真值都是接受的话,那么该ID就可以被接收,如果这11位中有一个真值是拒绝的话就表示该ID所代表的数据帧会被丢弃。该例中根据真值情况,控制器能接收id为0x20的标准报文,而不能接收其他id的报文。当然根据真值表,当用init_Mask(MCP_RXM0, 0, 0x7DF)把MCP_RXM0改为了0x7DF后,MCP_RXF0仍为0x20,此时根据真值表,can控制器可以接受即将到来的0x20数据帧。
返回值:如果初始化成功,则返回MCP_OK;反之,返回MCP_FA
使用方法:
init_Mask(MCP_RXM0, 0, 0x7ff); init_Filter(MCP_RXF0, 0, 0x04);//在init()函数之后,begin()之前使用,且和init_Mask()共同起作用。设置can控制器对标准帧id 0x04进行接收。
uint8_t readMsgBuf(uint8_t *len, uint8_t *buf)
函数功能:从MCP2515接收buffer中读取数据。
参数说明:
- len:保存接收到的数据长度。
- buf:保存接收到的数据。
返回值:如果返回CAN_OK,则表示读取数据成功;反之返回CAN_NOMSG。
使用方法:
在can总线工作起来后,如果有数据帧到来调用该函数可以把该数据帧读出来,参见后续章节样例。
uint8_t readMsgBufID(uint32_t *ID, uint8_t *len, uint8_t *buf)*
函数功能:从MCP2515接收buffer中读取数据,并读取此帧数据的id。
参数说明:
- ID : 保存此帧数据的id。
- len:保存接收到的数据长度。
- buf:保存接收到的数据。
返回值:如果返回CAN_OK,则表示读取数据成功;反之返回CAN_NOMSG。
使用方式:用法同readMsgBuf()函数类似只是多了一个ID用于返回该帧数据的ID号。
uint8_t checkError(void)
函数功能:检测MCP2515是否发送控制错误。
参数说明: 无。
返回值:如果发送了控制错误,则返回CAN_CTRLERROR;反之返回CAN_OK。
uint32_t getCanId(void) 函数说明:获取当前帧的id。
参数说明: 无。
返回值:帧id。
使用方式:当接收到数据后,调用此函数用于得到接收到的数据帧的ID,参见后续章节样例。
uint8_t isExtendedFrame(void) 函数说明:判断当前帧是否为扩展帧。
参数说明: 无
返回值:如果返回1,则表示当前帧为扩展帧;如果返回0,则表示当前帧是标准帧。 使用方式:在接收中断处理函数中调用,以判断数据帧是标准数据帧还是扩展帧。
7.实验教程
硬件准备
- DFRduino UNO R3 (SKU:DFR0216)x3
- CAN-BUS Shield V2.0(SKU:DFR0370)x3
- 杜邦线 x4
软件准备
- 下载Arduino IDE: 点击下载Arduino IDE
- 下载Arduino库:CAN-BUS Shield库文件 关于如何安装库文件:如何安装库?
基本的CAN收发功能(轮询接收)
本实验测试基本的CAN收发功能,其中接收采用轮询方式,可以接受任意id的标准数据帧或扩展帧。发射节点每隔100ms发送一帧id为0x06的标准数据帧。
实验接线
CAN-BUS Shield V2.0模块组网时,模块间连线为:CANH与CANH相连接,CANL与CANL相连接,如下图:
例程代码
接收端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while( CAN.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
}
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();
}
}
发射端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while( CAN.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
}
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
}
实验现象
接收方:串口输出:
基本收发功能(中断接收)
本实验测试基本收发功能,接收采用中断方式。
实验接线
例程代码
接收端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 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.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
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();
}
}
}
发射端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while( CAN.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
}
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
}
实验现象
接收方:串口中输出:
接受指定ID数据帧(中断接收)
本实验测试只接受初始化CAN模块时指定id的数据帧,接收采用中断方式。
实验接线
例程代码
接收端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 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.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
CAN.initMask(MCP2515_RXM0, 0, 0x3ff); // there are 2 mask in mcp2515, you need to set both of them
CAN.initMask(MCP2515_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.initFilter(MCP2515_RXF0, 0, 0x04); // filter 0 for id = 0x04
CAN.initFilter(MCP2515_RXF1, 0, 0x05); // filter 1 for id = 0x05
// CAN.initFilter(MCP2515_RXF2, 0, 0x06); // filter 2 for id = 0x06
CAN.initFilter(MCP2515_RXF3, 0, 0x07); // filter 3 for id = 0x07
CAN.initFilter(MCP2515_RXF4, 0, 0x08); // filter 4 for id = 0x08
CAN.initFilter(MCP2515_RXF5, 0, 0x09); // filter 5 for id = 0x09
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();
}
}
发射端点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while( CAN.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
}
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);
}
}
实验现象
接收方:串口输出:
注意:接收到的数据帧中既没有没有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相连接,如下图:
例程代码
Node 1例程
#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();
}
}
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_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();
}
}
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_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();
}
}
实验现象
CAN接收方串口不断输出下图信息:
实验现象分析: 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相连接,如下图:
例程代码
发送节点例程
#include "DFRobot_MCP2515.h"
const int SPI_CS_PIN = 10;
DFRobot_MCP2515 CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while( CAN.begin(CAN_500KBPS) ){ // init can bus : baudrate = 500k
Serial.println("DFROBOT's CAN BUS Shield init fail");
Serial.println("Please Init CAN BUS Shield again");
delay(3000);
}
Serial.println("DFROBOT's CAN BUS Shield init ok!\n");
}
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
}
接收节点例程
#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();
}
}
实验现象
接收方:串口输出:
实验现象分析:接收节点接收到id为0x60的数据帧,并将其存入到文件名为Node0x60.text文件中,然后关闭文件。最后又打开文件,并从文件中读出刚才收到的数据通过串口打印出来,如上图所示。
协议/库资料
常见问题
还没有客户对此产品有任何问题,欢迎通过qq或者论坛联系我们!
更多问题及有趣的应用,可以 访问论坛 进行查阅或发帖!