CAN Bus Local Area Network Tutorial


This tutorial will show you how to set up your own CAN Local Area Network using the CAN Bus shield! The CAN bus protocol is far superior to USART, SPI, and I2C because it uses a twisted pair to communicate between devices just like the Ethernet port on the back of your computer. This means it rejects noise very well and is great for electrically noisy environments like cars, planes, and even homes when data has to be transmitted long distances.

Can Bus Shield

Can Bus Shield

For this tutorial, we will use two Arduino Uno R3’s, paired with the CAN bus shields. We will also need a few LED’s and Ethernet cables, to connect the boards together. The shields come with headers needed to connect to the Arduino UNO, but does not come with the RJ-45 connectors you will need for this example. The mating connector should be available shortly on our website. The shield can also be used to connect to an existing CAN network, like the one found in your modern cars, but we will not be going over on how to do that in this tutorial.

Features of a CAN Network

Before we begin, here are some of the key features of CAN.

1) Each node is able to send and receive messages, but not simultaneously. 

2) A message consists primarily of an ID (identifier, in our code this is My_ID), which represents the priority of the   message, and up to eight data bytes.

3) It is transmitted serially onto the bus and is sensed by all nodes.

4) If the bus is free, any node may begin to transmit. If two or more nodes begin sending messages at the same time, the message with the more dominant ID (which has more dominant bits, i.e., zeroes) will overwrite other nodes' less dominant IDs, so that eventually (after this arbitration on the ID) only the dominant message remains and is received by all nodes (known as Bus Arbitration). Messages with numerically smaller values of IDs have higher priority and are transmitted first.


Alright, off to the fun part! Let's put everything together. We will start by setting two solder jumpers on both boards.

POE: The first thing we will do is solder the jumper labeled POE on the board, which stands for Power Over Ethernet. This will allow us to power only one board (either one), while the second one will receive power over the Ethernet cable. Without these jumpers enabled, you will need to provide separate power to both Arduino Boards. Using a soldering iron, you have to solder the two jumper pads together. The location of this jumper, as well as the Termination jumper you will need in the next step, is shown here circled in orange. 

Jumper Locations

Jumper Locations

Termination: The next step is to solder the termination jumper, which is required at the end points of the network. Since both are boards are going to be end nodes, they both need to have this jumper soldered to follow the CAN bus specifications. If we had a third board in the middle of the two, we would not solder this termination jumper for that board. Solder this jumper the same way you did the POE jumper.

Connectors: In this example we will simply solder one RJ-45 connector per board. It does not matter which one of the two spots you use as they both are identical. Start by soldering the Arduino headers since soldering the RJ-45 connector first would make it harder to keep the headers strait. Once you have finished soldering the headers, proceed to the RJ-45 connector; the finished board mounted on the Arduino UNO should look something like this.

Can/Arduino Assembled

Can/Arduino Assembled

Programming: The next step is programming up the devices and wiring a couple of LEDs. First thing you need to do is have the Arduino IDE installed on your computer and then add theCAN Bus libraryto it. The library has some examples built in, two of which will be used in this tutorial. The library handles all the difficult register reads and writes to the Microchip 2515 IC over SPI. All the user has to do is assemble packets to send over the bus as well as read package on the bus.

CAN TX: The CAN TX example is used in conjunction with the CAN RX code to fade an LED connected to Pin 9 of the Arduino UNO on the receiver side. The code is pretty simple; the UNO is calculating a fade value every 10ms to be sent over the CAN bus. Each packet transmitted over the CAN bus contains a Device ID, as well as 8 bytes of data. We will use the first data byte for the address of the device, and the second byte for the led brightness control of that device. 

Can TX Code:

#include <Canbus.h> unsigned int MY_ID = 0x0756; // This is the devices ID. The Lower the Number, the Higher its Priority on the CAN Bus. ID 0x0000 would be the highest Priority. (Cant have two with the same ID) //We wont use this for this example, but if you need to send messages back to the Master, we would need this // unsigned char MY_PID = 1; // This is the ID we will use to check if the message was for this device. int brightness = 0; // how bright the LED is int fadeAmount = 5; // how many points to fade the LED by unsigned char RX_Buff[8]; void setup() { Serial.begin(9600); Serial.println("CAN TX"); /* For debug use */ delay(1000); if(Canbus.init(CANSPEED_500)) /* Initialise MCP2515 CAN controller at the specified speed */ Serial.println("CAN Init ok"); else Serial.println("Can't init CAN"); delay(1000); } void loop() { //This is just a basic fading routine brightness = brightness + fadeAmount; if (brightness == 0 || brightness == 255) { fadeAmount = -fadeAmount ; } RX_Buff[0] = 10; // We want this message to be picked up by device with a PID of 10 RX_Buff[1] = brightness; // This is the brightness level we want our LED set to on the other device Canbus.message_tx(MY_ID,RX_Buff); // Send the message on the CAN Bus to be picked up by the other devices delay(10); }

The MY_ID variable is used to store the ID of this device; it basically sets the priority of this device. Any device on the bus with an address lower then this device would have bus priority. If two devices tried to transmit a packet at the same time, the one with the lower MY_ID would "Win", and the other would have to retry. We just chose a random 16 bit (non negative number) of 0x0756 to be its address.

The setup routine is used to initialize the CAN bus shield, by calling Canbus.init(speed). Once we get the "Can Init ok" we know that our shield is functioning properly. 

The second part of this code is simply calculating a fade value as shown in the "Fade" example that comes with the Arduino IDE. The difference is that we are now trying to control an LED connected to a different Arduino UNO. This is where the CAN network comes in handy! Once the fade value is calculated, we assemble a packet by setting the first byte of the RX_Buff to a devices' PID (10 in this example, we will see why in the RX code), and the second byte to hold the brightness level. Then we use the Canbus.message_tx to put the message on the CAN bus. We pass the buffer to the function, along with the MY_ID, so the other devices on the bus can see who the message came from. 

CAN RX: Now the RX side of things. The second UNO is simply sitting in a infinite loop to receive a message over the CAN bus. The TX is sending an updated brightness value ever 10ms, so there is a new message on the bus a 100 times a second!

Can RX Code:

#include <Canbus.h> unsigned int MY_ID = 0x0757; // This is the devices ID. The Lower the Number, the Higher its Priority on the CAN Bus. ID 0x0000 would be the highest Priority. (Cant have two with the same ID) unsigned char MY_PID = 10; // This is the ID we will use to check if the message was for this device. If you have more than one UNO with the same PID, they will all accept the message. int LED = 9; // Our LED Pin unsigned char RX_Buff[8]; // Buffer to store the incoming data void setup() { Serial.begin(9600); // For debug use Serial.println("CAN RX"); delay(1000); if(Canbus.init(CANSPEED_500)) /* Initialise MCP2515 CAN controller at the specified speed */ Serial.println("CAN Init ok"); else Serial.println("Can't init CAN"); delay(1000); } void loop() { unsigned int ID = Canbus.message_rx(RX_Buff); // Check to see if we have a message on the Bus if (RX_Buff[0] == MY_PID) // If we do, check to see if the PID matches this device. We are using location (0) to transmit the PID and (1) for the LED's duty cycle analogWrite(LED, RX_Buff[1]); // If it does check what the LED's duty cycle should be set to, and set it! We are done! }

On this side, you will notice the MY_ID is different. We need a different MY_ID if we plan on transmitting from this node on the bus. Since this example is only going to receive, it is there just for notation sake. The next value is MY_PID, this is the ID which the device will respond to. The nice thing about this is that we can have many nodes with the same MY_PID (say we need two devices to do the same thing when a message is received). We have to be careful not to have two devices trying to transmit at the same time, but in this case it does not matter. We have randomly picked 10, but it can be anything between 0-255. This is why we load the RX_Buff[0] with 10 on the TX side. 

The setup loop is simply setting up our CAN bus shield, as well as the Serial debugger so we can see what's going on; nothing special there. 

Now the loop, there is where we sit waiting for a message. We call Canbus.message_rx and pass an RX_Buff array to the function. It will fill the buffer with the data received on the bus, as well as return the ID of the device the message came from. In this case, all we have is one other device, so we can ignore the ID. Once the buffer is full, we use an if statement to test for the matching My_PID. If the ID matches, it sets the brightness of the LED connected to Pin 9. That's it!

Connect it all up: So now that you understand how the code works, lets connect everything up and give it a shot! Go ahead and program one UNO (either one) with the TX code, and the other with the RX code. Once you upload the code for each one, open up the serial communicator and make sure you're getting the "CAN Init ok" message. If you do on both sides, you are ready to disconnect from your computer and give it a shot! Simply connect both boards with a straight through Ethernet cable (not like your Ethernet shield which connects to your home network), and attach the LED's anode to Pin 9 of the receiving UNO and the cathode lead to GND. Lastly, you will need a power source. The easiest way is to power one of the two UNOs is with a DC wall adapter. The complete setup should look like this:

Complete Setup

Complete Setup

And there you have it, one UNO contolling the other UNO's LED over a CAN bus! The UNO on the left is controlling the LED of the UNO on the right. And just to show you how awesome this really is, here is a picture of a third UNO, we simple soldered up both RJ-45 connectors to make a bridge, loaded the CAN RX example on it, and threw it in the loop!



Both of the receivers are programmed with the same PID, so they are both responding to the message by setting the LED's intensity to the same value. We could have just as easily given this third UNO a new PID, and sent a different message to it.

In this example, we are just controlling one LED, but CAN bus is used in your car to link engines and transmission together, as well as AC units, gauges, and just about everything with a microcontroller in your car is on it's CAN network. The possibilities here are endless! I hope you enjoyed this tutorial, and have learned a thing or two about the CAN bus. If you have any questions about this tutorial, don't hesitate to post a comment, shoot us an email, or post it in our forum!

This article was published by the Jaycon team. Learn more about how we can take your product design and hardware idea to the next level here.