Arduino MCP2515 CAN Bus Interface Tutorial - CAN Protocol
Arduino MCP2515 CAN Bus Interface Tutorial - CAN Protocol
In this project, we will learn about the MCP2515 CAN Controller Module, how to interface the MCP2515 CAN Bus Controller with Arduino
and nally how to enable communication between two Arduino board with the help of two MCP2515 CAN Controllers and the CAN
Protocol.
Outline
Introduction
Controlled Area Network of simple CAN is a bus standard that allows a Microcontroller and its peripheral devices to communicate without
the need of a host device or a computer.
1000 Cartões só
Compre Agora R$58,27
360imprimir
Developed by Robert Bosch GmbH, CAN is protocol is main used in automobiles for communication between a control unit and its
components.
For example, the Engine Control Unit is a major control using in a car. This unit is connected to many sensors and actuators like air ow,
pressure, temperature, valve control, motors for air control etc. The communication between these modules and the control unit is
through CAN Bus.
In order to understand a little bit more about CAN Bus, CAN Controller and other important aspects, the MCP2515 CAN Bus Controller
Module is very helpful.
This particular module is based on MCP2515 CAN Controller IC and TJA1050 CAN Transceiver IC. The MCP2515 IC is a standalone CAN
Controller and has integrated SPI Interface for communication with microcontrollers.
Coming to the TJA1050 IC, it acts as an interface between the MCP2515 CAN Controller IC and the Physical CAN Bus.
The following image shows the components and pins on a typical MCP2515 Module.
MCP2515 IC is the main controller that internally consists of three main subcomponents: The CAN Module, the Control Logic and the SPI
Block.
CAN Module is responsible for transmitting and receiving messages on the CAN Bus. Control Logic handles the setup and operation of the
MCP2515 by interfacing all the blocks. The SPI Block is responsible for the SPI Communication interface.
Coming to the TJA1050 IC, since it acts as an interface between MCP2515 CAN Controller and the physical CAN Bus, this IC is responsible
for taking the data from the controller and relaying it on to the bus.
The following image shows the schematic of the MCP2515 CAN Module and it shows how MCP2515 IC and TJA1050 IC are connected on
the Module.
If the pins of the MCP2515 Module are not clear, the following image might be useful.
Components Required
Arduino UNO x 2 [Buy Here]
MCP2515 x 2
USB Cable x 2
Connecting Wires
Circuit Design
As mentioned earlier, the CAN Controller IC facilitates SPI Communication Protocol for interfacing with any Microcontroller. Hence, connect
the SPI Pin i.e. SCK, MOSI (SI), MISO (SO) and CS of the MCP2515 Module to corresponding SPI Pins of Arduino (see circuit diagram).
Make two such connections: one pair acts as a transmitter and the other as a receiver. Now for the communication between this
transmitter and receiver, connect CANH and CANL pins of each MCP2515 Module.
Code
Before going into the code, you need to download a library for the MCP2515 Module. There are many libraries but I have used this
particular one.
Download it and place the extracted contents in the libraries directory of Arduino.
Since the communication involves a Transmitter Module and a Receiver Module, the code is also divided into Transmitter Code and Receiver
Code.
Transmitter Code
1 #include <SPI.h>
2 #include <mcp_can.h>
3
4 const int spiCSPin = 10;
5 int ledHIGH = 1;
6 int ledLOW = 0;
7
8 MCP_CAN CAN(spiCSPin);
9
10 void setup()
11 {
12 Serial.begin(115200);
13
14 while (CAN_OK != CAN.begin(CAN_500KBPS))
15 {
16 Serial.println("CAN BUS init Failed");
17 delay(100);
18 }
19 Serial.println("CAN BUS Shield Init OK!");
20 }
21
22 unsigned char stmp[8] = {ledHIGH, 1, 2, 3, ledLOW, 5, 6, 7};
23
24 void loop()
25 {
26 Serial.println("In loop");
27 CAN.sendMsgBuf(0x43, 0, 8, stmp);
28 delay(1000);
29 }
Receiver Code
1 #include <SPI.h>
2 #include "mcp_can.h"
3
4 const int spiCSPin = 10;
5 const int ledPin = 2;
6 boolean ledON = 1;
7
8 MCP_CAN CAN(spiCSPin);
9
10 void setup()
11 {
12 Serial.begin(115200);
13 pinMode(ledPin,OUTPUT);
14
15 while (CAN_OK != CAN.begin(CAN_500KBPS))
16 {
17 Serial.println("CAN BUS Init Failed");
18 delay(100);
19 }
20 Serial.println("CAN BUS Init OK!");
21 }
22
23
24 void loop()
25 {
26 unsigned char len = 0;
27 unsigned char buf[8];
28
29 if(CAN_MSGAVAIL == CAN.checkReceive())
30 {
31 CAN.readMsgBuf(&len, buf);
32
33 unsigned long canId = CAN.getCanId();
34
35 Serial.println("-----------------------------");
36 Serial.print("Data from ID: 0x");
37 Serial.println(canId, HEX);
38
39 for(int i = 0; i<len; i++)
40 {
41 Serial.print(buf[i]);
42 Serial.print("\t");
43 if(ledON && i==0)
44 {
45
46 digitalWrite(ledPin, buf[i]);
47 ledON = 0;
48 delay(500);
49 }
50 else if((!(ledON)) && i==4)
51 {
52
53 digitalWrite(ledPin, buf[i]);
54 ledON = 1;
55 }
56 }
57 Serial.println();
58 }
59 }
Working
Working of this project is very simple as all the work is done by the libraries (SPI and CAN). Since CAN is message-based communication,
you need to send a message anywhere between 0 and 8 bytes.
In this project, the transmitter is sending a message as 1 1 2 3 0 5 6 7. This message is transmitted over CAN Bus and the receiver receives
this message and is displayed on its serial monitor.
Additionally, the 0th and 4th bit i.e. 1 and 0 in the above sequence are extracted separately by the receiver and turns ON and OFF the LED
connected to Pin 2 of Arduino.
Applications
As mentioned in the introduction, CAN is widely used in the eld of automobiles. Some of the applications include:
Related Posts:
ESP32 DS18B20 Tutorial | DS18B20 Temperature Sensor…
Interfacing MFRC522 RC522 RFID Reader Module with Arduino
ESP32 BMP180 Sensor Tutorial | How to Interface…
How to use BLE in ESP32? ESP32 BLE (Bluetooth Low…
ESP32 DHT11 Tutorial | DHT11 Humidity Temperature…
Automatic Room Lights using Arduino and PIR Sensor
18 Responses
Thank you for the information. Getting 2 Arduinos+MCP talking to each other is interesting and simple. The challenge
happens when you connect to the OBDII port of a vehicle. That’s when according to my experience, things get a lot more
complicated:
– Vehicles can use standard CAN frames or extended ones (I’m not quite sure the Seeed library works with extended CAN
frames).
– Even with vehicles that use standard CAN frames, when you send the PID asking for example for the engine’s RPMs, it
seems the vehicle doesn’t receive the data.
Thanks,
Dave
Reply
Reply
Hey! It seems very nice the example that you shows. I just want to know if I can codify one Arduino as transmitter and
receiver at the same time.
Thanks!!
Paula
Reply
Luke says:
↪
Hi. I am after something similar to Paula. In my case I am interested in running two CAN modules from the one Arduino
– either in a dual-bus car (HSCAN=500kbps, MSCAN=125kbps) or as an isolating CAN bridge – for example, when an
Elctro-Hydraulic Power Steering Pump from a different model that needs CAN translation of broadcasts to work but
must not see the original messages of the new vehicle. While SPI is fine for multiple modules, I think I am struggling to
find a library that supports multiple CAN interfaces at the same time.
Luke
Reply
You can connect to 2 MC2515 shiles by creating 2 different objects like this:
MCP_CAN CAN_ONE(spiCSPin1);
MCP_CAN CAN_TWO(spiCSPin2);
So, you can initialize the two modules with different spees for CANbus. etc and you can read and write separately.
You may need additional pins if you rely on Interrupt pin to notify you about received messages. In that case you
may use pins 2 and 3 . Otherwise you can relay on frequent polling of the 2 modules. However, have in mind also
programming is more complicated with 2 modules and the MCU could be overloaded
Reply
Alexandre says:
Hi Paula!
could you solve your issue? I need something like that!
Thanks!
Alexandre
Reply
Hello,
My project like this, however I using lm 35 tem. sensor. But I couln’t write code. How can ı write ?
Reply
Alex says:
Hi
If I need to send message, then receive an answer, repack answer into different packet and send it back – how to do it in a
single sketch?
Reply
I’m in a University Project, in wich we build an eletric motorcycle , communication are made with CAN. I have used half of
your project to try and read the BUS CAN, but it can´t even pass the begin.CAN loop. From what i have seen in the web it
may be due to crystal being a 8oooKhz and the library is made for 16000Khz. Can you help me?
Reply
/*********************************************************************************************************
** Function name: mcp2515_configRate
** Descriptions: set baudrate
*********************************************************************************************************/
byte mcp2515_can::mcp2515_configRate(const byte canSpeed, const byte clock) {
byte set, cfg1, cfg2, cfg3;
set = 1;
switch (clock) {
case (MCP_16MHz) :
switch (canSpeed) {
case (CAN_5KBPS):
cfg1 = MCP_16MHz_5kBPS_CFG1;
cfg2 = MCP_16MHz_5kBPS_CFG2;
cfg3 = MCP_16MHz_5kBPS_CFG3;
break;
case (CAN_10KBPS):
cfg1 = MCP_16MHz_10kBPS_CFG1;
cfg2 = MCP_16MHz_10kBPS_CFG2;
cfg3 = MCP_16MHz_10kBPS_CFG3;
break;
case (CAN_20KBPS):
cfg1 = MCP_16MHz_20kBPS_CFG1;
cfg2 = MCP_16MHz_20kBPS_CFG2;
cfg3 = MCP_16MHz_20kBPS_CFG3;
break;
case (CAN_25KBPS):
cfg1 = MCP_16MHz_25kBPS_CFG1;
cfg2 = MCP_16MHz_25kBPS_CFG2;
cfg3 = MCP_16MHz_25kBPS_CFG3;
break;
case (CAN_31K25BPS):
cfg1 = MCP_16MHz_31k25BPS_CFG1;
cfg2 = MCP_16MHz_31k25BPS_CFG2;
cfg3 = MCP_16MHz_31k25BPS_CFG3;
break;
case (CAN_33KBPS):
cfg1 = MCP_16MHz_33kBPS_CFG1;
cfg2 = MCP_16MHz_33kBPS_CFG2;
cfg3 = MCP_16MHz_33kBPS_CFG3;
break;
case (CAN_40KBPS):
cfg1 = MCP_16MHz_40kBPS_CFG1;
cfg2 = MCP_16MHz_40kBPS_CFG2;
cfg3 = MCP_16MHz_40kBPS_CFG3;
break;
case (CAN_50KBPS):
cfg1 = MCP_16MHz_50kBPS_CFG1;
cfg2 = MCP_16MHz_50kBPS_CFG2;
cfg3 = MCP_16MHz_50kBPS_CFG3;
break;
case (CAN_80KBPS):
cfg1 = MCP_16MHz_80kBPS_CFG1;
cfg2 = MCP_16MHz_80kBPS_CFG2;
cfg3 = MCP_16MHz_80kBPS_CFG3;
break;
case (CAN_83K3BPS):
cfg1 = MCP_16MHz_83k3BPS_CFG1;
cfg2 = MCP_16MHz_83k3BPS_CFG2;
cfg3 = MCP_16MHz_83k3BPS_CFG3;
break;
case (CAN_95KBPS):
cfg1 = MCP_16MHz_95kBPS_CFG1;
cfg2 = MCP_16MHz_95kBPS_CFG2;
cfg3 = MCP_16MHz_95kBPS_CFG3;
break;
case (CAN_100KBPS):
cfg1 = MCP_16MHz_100kBPS_CFG1;
cfg2 = MCP_16MHz_100kBPS_CFG2;
cfg3 = MCP_16MHz_100kBPS_CFG3;
break;
case (CAN_125KBPS):
cfg1 = MCP_16MHz_125kBPS_CFG1;
cfg2 = MCP_16MHz_125kBPS_CFG2;
cfg3 = MCP_16MHz_125kBPS_CFG3;
break;
case (CAN_200KBPS):
cfg1 = MCP_16MHz_200kBPS_CFG1;
cfg2 = MCP_16MHz_200kBPS_CFG2;
cfg3 = MCP_16MHz_200kBPS_CFG3;
break;
case (CAN_250KBPS):
cfg1 = MCP_16MHz_250kBPS_CFG1;
cfg2 = MCP_16MHz_250kBPS_CFG2;
cfg3 = MCP_16MHz_250kBPS_CFG3;
break;
case (CAN_500KBPS):
cfg1 = MCP_16MHz_500kBPS_CFG1;
cfg2 = MCP_16MHz_500kBPS_CFG2;
cfg3 = MCP_16MHz_500kBPS_CFG3;
break;
case (CAN_666KBPS):
cfg1 = MCP_16MHz_666kBPS_CFG1;
cfg2 = MCP_16MHz_666kBPS_CFG2;
cfg3 = MCP_16MHz_666kBPS_CFG3;
break;
case (CAN_1000KBPS):
cfg1 = MCP_16MHz_1000kBPS_CFG1;
cfg2 = MCP_16MHz_1000kBPS_CFG2;
cfg3 = MCP_16MHz_1000kBPS_CFG3;
break;
default:
set = 0;
break;
}
break;
case (MCP_8MHz) :
switch (canSpeed) {
case (CAN_5KBPS) :
cfg1 = MCP_8MHz_5kBPS_CFG1;
cfg2 = MCP_8MHz_5kBPS_CFG2;
cfg3 = MCP_8MHz_5kBPS_CFG3;
break;
case (CAN_10KBPS) :
cfg1 = MCP_8MHz_10kBPS_CFG1;
cfg2 = MCP_8MHz_10kBPS_CFG2;
cfg3 = MCP_8MHz_10kBPS_CFG3;
break;
case (CAN_20KBPS) :
cfg1 = MCP_8MHz_20kBPS_CFG1;
cfg2 = MCP_8MHz_20kBPS_CFG2;
cfg3 = MCP_8MHz_20kBPS_CFG3;
break;
case (CAN_31K25BPS) :
cfg1 = MCP_8MHz_31k25BPS_CFG1;
cfg2 = MCP_8MHz_31k25BPS_CFG2;
cfg3 = MCP_8MHz_31k25BPS_CFG3;
break;
case (CAN_40KBPS) :
cfg1 = MCP_8MHz_40kBPS_CFG1;
cfg2 = MCP_8MHz_40kBPS_CFG2;
cfg3 = MCP_8MHz_40kBPS_CFG3;
break;
case (CAN_50KBPS) :
cfg1 = MCP_8MHz_50kBPS_CFG1;
cfg2 = MCP_8MHz_50kBPS_CFG2;
cfg3 = MCP_8MHz_50kBPS_CFG3;
break;
case (CAN_80KBPS) :
cfg1 = MCP_8MHz_80kBPS_CFG1;
cfg2 = MCP_8MHz_80kBPS_CFG2;
cfg3 = MCP_8MHz_80kBPS_CFG3;
break;
case (CAN_100KBPS) :
cfg1 = MCP_8MHz_100kBPS_CFG1;
cfg2 = MCP_8MHz_100kBPS_CFG2;
cfg3 = MCP_8MHz_100kBPS_CFG3;
break;
case (CAN_125KBPS) :
cfg1 = MCP_8MHz_125kBPS_CFG1;
cfg2 = MCP_8MHz_125kBPS_CFG2;
cfg3 = MCP_8MHz_125kBPS_CFG3;
break;
case (CAN_200KBPS) :
cfg1 = MCP_8MHz_200kBPS_CFG1;
cfg2 = MCP_8MHz_200kBPS_CFG2;
cfg3 = MCP_8MHz_200kBPS_CFG3;
break;
case (CAN_250KBPS) :
cfg1 = MCP_8MHz_250kBPS_CFG1;
cfg2 = MCP_8MHz_250kBPS_CFG2;
cfg3 = MCP_8MHz_250kBPS_CFG3;
break;
case (CAN_500KBPS) :
cfg1 = MCP_8MHz_500kBPS_CFG1;
cfg2 = MCP_8MHz_500kBPS_CFG2;
cfg3 = MCP_8MHz_500kBPS_CFG3;
break;
case (CAN_1000KBPS) :
cfg1 = MCP_8MHz_1000kBPS_CFG1;
cfg2 = MCP_8MHz_1000kBPS_CFG2;
cfg3 = MCP_8MHz_1000kBPS_CFG3;
break;
default:
set = 0;
break;
}
break;
default:
set = 0;
break;
}
if (set) {
mcp2515_setRegister(MCP_CNF1, cfg1);
mcp2515_setRegister(MCP_CNF2, cfg2);
mcp2515_setRegister(MCP_CNF3, cfg3);
return MCP2515_OK;
} else {
return MCP2515_FAIL;
}
}
Reply
Reply
Sven says:
↪
It’s not the arduino which has the address, it’s the application. When your specific arduino runs the „application“ with a
fix Id, you can address that.
So you need to design your application about the messages which you wand to send. E.g.: turn lamp on, ID 0x45, turn
off lamp ID 0x46. Turn on horn, 0x10 – send every 10ms if not horn turns off. In a Car normally you send every X ms a
message to tun on a front light if the message is not send, the lamp turn off. It depends on the security function of your
application.
Reply
Deepak says:
Hi,
I have copied the exact code for transmitter and receiver Code, and downloaded the related libraries for as mentioned
above.
However, while compiling error message ‘cannot declare variable CAN to be of abstract type MCP_CAN’
Reply
Balazs says:
↪
Hi,
Did you find out the solution?
I have the same error 🙁
Could you share how to fix it?
Reply
Balazs says:
↪
I found the solution in the examples.
#include
#include “mcp2518fd_can.h”
It works now.
Reply
rashi says:
↪
Can you please share the code. actually, I’m doing something similar to it.
I am trying to communicate the CAN messages from a battery. so i just need to have the receiver side of code.
but its not working. its just displaying the same value every-time.
Can you please help me out.
Reply
Sudh says:
Reply
Tom says:
Hi, can anyone help me and let me know what modifications I need to do in order to allow this to work with arduino mega?
I have tried using the same pins and same code, but keep getting the message
“CAN BUS init Failed”
Thanks,
Tom
Reply
Leave a Reply
Your email address will not be published. Required fields are marked *
Comment *
Name *
Email *
Website
Post Comment