https://en.wikipedia.org/wiki/CAN_bus
We make custom stm32 boards that have onboard CAN transceivers that send and receive CAN messages.
We use the CANable device to send CAN messages over USB.
https://canable.io/
The CAN bus is a differential asynchronous communication protocol that is often used in automotive applications. The bus supports a transfer rate of up to 1 Mbit/s. The nodes are not individually addressed. The bus operates on an ID-based priority system. Messages with lower IDs are prioritized on the bus. A message is queued if it does not have priority. IDs from 0-10 are used for prioritizing the safety systems for the IGVC robot. 3.3V and 5V transceivers are interoperable because the bus is differential. The following figure is an example of a message sent over the bus.
Image screenshot from Wikipedia.
We use Mbed studio as our main development software to program and debug our STM32 boards. Check out our Mbed Studio page to get help setting up your environment. The Mbed library that is packaged with Mbed studio will be used in our example. Make sure your STM32 device supports the usage of the CAN bus before moving on. Some devices don't have an onboard CAN transceiver, so you have to use an external CAN transceiver to communicate on the bus. Here is the CAN transceiver that we use in SCR.
The CAN bus requires that 120-ohm resistors terminate both ends of the bus. Here is an example of what your schematic might look like. This example uses an LPC1768 board with two external can transceivers. This schematic creates a loop between the two nodes on the bus.
Image screenshot from Mbed.
The following example code sends a message out every second while constantly polling for a new message to read off of the bus. The device toggles a LED when it receives and reads a new message. You can find out about the Mbed CAN API here.
For most purposes, we are going to use the Mbed libraries.
#include "mbed.h"
We are using the built-in Ticker class to call a function every second. Ticker API
Ticker ticker; // Ticker for mbed.
Most Development boards have an onboard LED that you can control using code. We are using the LED as an indicator to show the user that it received a message.
DigitalOut led1(PC_13); // LED is attached to PC_13
We initialized our CAN bus and it uses PA_11 and PA_12 for the RX/TX pins for the transceiver. The 3rd argument is the bitrate.
CAN can1(PA_11, PA_12, 100000); // PA_11 and PA_12 are attached to the CAN transceiver. This sends at a rate of 100 Kbit/s
This is going to be the data that we send out over the bus.
char blank = 0; //blank message
This function sends a message over the can bus. The Can.write function takes in 3 arguments. ID, Char pointer for data, and the length in bytes of the data. The function returns a 1 if the message was sent successfully. Otherwise, it returns 0.
int send_msg(){
if(can1.write(CANMessage(2, &blank, 0))) // sends the data in blank with ID = 2, Data = blank, and length = 0
return 1;
return -1;
}
The receiving message is initialized. We will write the data of the message when we receive a message over the bus. We then attach the Ticker function to the send_msg function and tell it to call the function every second.
CANMessage msg; //Creates a new can message named msg
ticker.attach(&send_msg, 1); // this calls the send_msg function every second
We check to see if there is a message that is ready to read every .2 seconds. If a message is read successfully then the led is toggled.
while(1) {
if(can1.read(msg)){
led1 = !led1;
}
HAL_Delay(200); // Waits 200 ms
}
#include "mbed.h"
Ticker ticker; // Ticker for mbed.
DigitalOut led1(PC_13); // LED is attached to PC_13
CAN can1(PA_11, PA_12, 100000); // PA_11 and PA_12 are attached to the CAN transceiver. This sends at a rate of 100 Kbit/s
char blank = 0; //blank message
// This function sends a message over the can bus.
int send_msg(){
if(can1.write(CANMessage(2, &blank, 0))) // sends the data in blank with ID = 2, Data = blank, and length = 0
return 1;
return -1;
}
int main()
{
CANMessage msg; //Creates a new can message named msg
ticker.attach(&send_msg, 1); // this calls the send_msg function every second
while(1) {
if(can1.read(msg)){
led1 = !led1;
}
HAL_Delay(200); // Waits 200 ms
}
}
Code example from Tyler Julian.