CANBUS
The article provides a comprehensive guide on using the Edge101 development board for CAN Bus communication, covering both data reception and transmission, along with example codes and hardware setup requirements.
CAN Communication
Example1: CAN Bus Reception
This example demonstrates how the Edge101 development board uses the CAN Bus to receive frame data and determine the type of the frame. The user can also turn off the CAN Bus functionality using a user button.
Hardware Requirements:
- ESP32 IoT Programmable Controller (SKU: DFR0886)×1
- USB-CAN Converter ×1
Hardware Connection:

Example Code:
#include "DFRobot_ESP32CAN.h"
DFRobot_ESP32CAN ESP32Can;
uint8_t userKey = 38;
can_message_t message;
// External interrupt function to stop CAN
void interEvent(void){
ESP32Can.clearReceiveQueue(); // Clear the RX queue
ESP32Can.stop(); // Stop the CAN driver to prevent further transmission and reception
ESP32Can.release(); // Unload the CAN driver
detachInterrupt(userKey); // Detach the interrupt from the specified pin
}
void setup() {
pinMode(userKey, INPUT_PULLUP);
attachInterrupt(userKey,interEvent,CHANGE);
Serial.begin(115200);
/* Please refer to the structure can_general_config_t in DFRobot_ESP32CAN.h and CAN_GENERAL_CONFIG_DEFAULT(op_mode) for further understanding and modification.
Function: Change CAN mode
Modes:
CAN_MODE_NORMAL Normal send/receive/acknowledge mode
CAN_MODE_NO_ACK Send without acknowledgment mode, used for self-testing
CAN_MODE_LISTEN_ONLY Listen-only mode (no sending or acknowledgment, but can receive messages)
*/
can_general_config_t g_config = CAN_GENERAL_CONFIG(CAN_MODE_NORMAL); // Set the general configuration for initialization
/* Please refer to the structure can_timing_config_t in DFRobot_ESP32CAN.h and CAN_TIMING_CONFIG_500KBITS() for further understanding and modification.
Function: Change baud rate
Available baud rates:
CAN_TIMING_CONFIG_25KBITS()
CAN_TIMING_CONFIG_50KBITS()
CAN_TIMING_CONFIG_100KBITS()
CAN_TIMING_CONFIG_125KBITS()
CAN_TIMING_CONFIG_250KBITS()
CAN_TIMING_CONFIG_500KBITS()
CAN_TIMING_CONFIG_800KBITS()
CAN_TIMING_CONFIG_1MBITS()
*/
can_timing_config_t t_config = CAN_TIMING_CONFIG_500KBITS(); // Set the timing configuration for initialization
/* Please refer to the structure can_filter_config_t in DFRobot_ESP32CAN.h and CAN_FILTER_CONFIG_ACCEPT_ALL() for further understanding and modification.
CAN_FILTER_CONFIG_ACCEPT_ALL() {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true}
Function: Configure filter. The default mask is all 1s, meaning that identifiers must match exactly to be received.
*/
can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
// Initialize with the configured parameters
while(!ESP32Can.init(&g_config,&t_config,&f_config)){
Serial.println("CAN init err!!!");
delay(1000);
}
// Install CAN driver, reset RX and TX queues, and reset RX message count
while(!ESP32Can.start()){
Serial.println("CAN start err!!!");
delay(1000);
}
}
void loop() {
// Receive message function, message is the CAN message on the bus, pdMS_TO_TICKS() sets the blocking time, waiting for the desired data (in milliseconds)
if(ESP32Can.receive(&message,pdMS_TO_TICKS(1000))){
// Check the received ID, multiple IDs can be accepted using '||'
if(message.identifier == 0x0006){
/* Refer to Message flags in DFRobot_ESP32CAN.h
flags:
CAN_MSG_FLAG_NONE Standard format
CAN_MSG_FLAG_EXTD Extended format
CAN_MSG_FLAG_RTR Remote frame (Remote Transmit Request)
CAN_MSG_FLAG_SS Single Shot Transmission
CAN_MSG_FLAG_SELF Self Reception Request
*/
if (message.flags == CAN_MSG_FLAG_NONE) {
Serial.println("Message is in Standard Format");
} else if(message.flags == CAN_MSG_FLAG_EXTD){
Serial.println("Message is in Extended Format");
} else if(message.flags == CAN_MSG_FLAG_RTR){
Serial.println("Message is a Remote Transmit Request");
} else if(message.flags == CAN_MSG_FLAG_SS){
Serial.println("Transmit as a Single Shot Transmission");
} else if(message.flags == CAN_MSG_FLAG_SELF){
Serial.println("Transmit as a Self Reception Request");
} else if(message.flags == CAN_MSG_FLAG_DLC_NON_COMP){
Serial.println("Message's Data length code is larger than 8. This breaks CAN2.0B compliance");
}
// message.data_length_code is by default set to 5 characters in g_config for data transmission
for (int i = 0; i < message.data_length_code; i++) {
Serial.printf("Data byte %d = %d\n", i, message.data[i]);
}
} else {
printf("Error ID:%d\n", message.identifier);
}
} else {
Serial.println("Failed to queue message for receive");
}
delay(10);
}
After uploading the code, use a USB CAN analyzer to send data to the development board.

Results:
The CAN bus on the development board A receives the data and outputs it via the USB serial port.

Example2: CAN Bus Transmission
This example demonstrates how the Edge101 development board uses the CAN Bus to send standard frame data. The user can also turn off the CAN Bus functionality using a user button.
Example Code:
/*!
* @file can_send.ino
* @brief This demo demonstrates the FireBeetle MESH - Industrial IoT Mainboard using CAN to send standard frame data. The CAN functionality can be turned off using a user button.
* @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
* @licence The MIT License (MIT)
* @author [yangfeng]<[email protected]>
* @version V1.0
* @date 2021-04-08
* @get from https://www.dfrobot.com
*/
#include "DFRobot_ESP32CAN.h"
DFRobot_ESP32CAN ESP32Can;
uint8_t userKey = 38;
can_message_t tx_message;
void interEvent(void){
ESP32Can.stop();
ESP32Can.release();
detachInterrupt(userKey);
}
void setup() {
pinMode(userKey, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(userKey), interEvent, CHANGE); //Enable external interrupts
Serial.begin(9600);
/** Here we provide annotations for the can_general_config_t structure. For the MESH development board, the default CAN transmit and receive I/O pins are GPIO_35 and GPIO_32.
*
* typedef struct {
* can_mode_t mode; < Mode of CAN controller
* gpio_num_t tx_io; < Transmit GPIO number
* gpio_num_t rx_io; < Receive GPIO number
* gpio_num_t clkout_io; < CLKOUT GPIO number (optional, set to -1 if unused)
* gpio_num_t bus_off_io; < Bus off indicator GPIO number (optional, set to -1 if unused)
* uint32_t tx_queue_len; < Number of messages TX queue can hold (set to 0 to disable TX Queue)
* uint32_t rx_queue_len; < Number of messages RX queue can hold
* uint32_t alerts_enabled; < Bit field of alerts to enable
* uint32_t clkout_divider; < CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused)
* int intr_flags; < Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_CAN_ISR_IN_IRAM option should be enabled first.
* } can_general_config_t;
*
* mode:
* CAN_MODE_NORMAL, < Normal operating mode where CAN controller can send/receive/acknowledge messages
* CAN_MODE_NO_ACK, < Transmission does not require acknowledgment. Use this mode for self-testing
* CAN_MODE_LISTEN_ONLY, < The CAN controller will not influence the bus (No transmissions or acknowledgments) but can receive messages
*
* CAN_GENERAL_CONFIG_DEFAULT(op_mode) {.mode = op_mode, .tx_io = GPIO_NUM_32, .rx_io = GPIO_NUM_35, \
* .clkout_io = CAN_IO_UNUSED, .bus_off_io = CAN_IO_UNUSED, \
* .tx_queue_len = 5, .rx_queue_len = 5, \
* .alerts_enabled = CAN_ALERT_NONE, .clkout_divider = 0, \
* .intr_flags = ESP_INTR_FLAG_LEVEL1}
*/
can_general_config_t g_config = CAN_GENERAL_CONFIG(CAN_MODE_NORMAL);
/** Here we provide annotations for the can_timing_config_t structure. Users can directly use initialization macros to configure the CAN communication speed.
* typedef struct {
* uint32_t brp; < Baudrate prescaler (i.e., APB clock divider) can be any even number from 2 to 128.
* For ESP32 Rev 2 or later, multiples of 4 from 132 to 256 are also supported
* uint8_t tseg_1; < Timing segment 1 (Number of time quanta, between 1 to 16)
* uint8_t tseg_2; < Timing segment 2 (Number of time quanta, 1 to 8)
* uint8_t sjw; < Synchronization Jump Width (Max time quanta jump for synchronization from 1 to 4)
* bool triple_sampling; < Enables triple sampling when the CAN controller samples a bit
* } can_timing_config_t;
*
* CAN_TIMING_CONFIG_25KBITS() {.brp = 128, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_50KBITS() {.brp = 80, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_100KBITS() {.brp = 40, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_125KBITS() {.brp = 32, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_250KBITS() {.brp = 16, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_500KBITS() {.brp = 8, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_800KBITS() {.brp = 4, .tseg_1 = 16, .tseg_2 = 8, .sjw = 3, .triple_sampling = false}
* CAN_TIMING_CONFIG_1MBITS() {.brp = 4, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}
*/
can_timing_config_t t_config = CAN_TIMING_CONFIG_500KBITS();
/** Here we provide annotations for the can_filter_config_t structure. Users can directly use initialization macros to configure the reception filter.
*
* typedef struct {
* uint32_t acceptance_code; < 32-bit acceptance code
* uint32_t acceptance_mask; < 32-bit acceptance mask
* bool single_filter; < Use Single Filter Mode
* } can_filter_config_t;
*
* CAN_FILTER_CONFIG_ACCEPT_ALL() {.acceptance_code = 0, .acceptance_mask = 0xFFFFFFFF, .single_filter = true}
*
*/
can_filter_config_t f_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
while(!ESP32Can.init(&g_config,&t_config,&f_config)){
Serial.println("CAN init err!!!");
delay(1000);
}
while(!ESP32Can.start()){
Serial.println("CAN start err!!!");
delay(1000);
}
ESP32Can.clearTransmitQueue();
tx_message.identifier = 0x0006;
tx_message.data_length_code = 4;
/** flags:
* CAN_MSG_FLAG_NONE < No message flags (Standard Frame Format)
* CAN_MSG_FLAG_EXTD < Extended Frame Format (29bit ID)
* CAN_MSG_FLAG_RTR < Message is a Remote Transmit Request
* CAN_MSG_FLAG_SS < Transmit as a Single Shot Transmission
* CAN_MSG_FLAG_SELF < Transmit as a Self Reception Request
*/
tx_message.flags = CAN_MSG_FLAG_NONE;
tx_message.data[0] = 0;
tx_message.data[1] = 1;
tx_message.data[2] = 2;
tx_message.data[3] = 3;
}
void loop() {
if(ESP32Can.transmit(&tx_message, pdMS_TO_TICKS(1000))){
Serial.println("Message queued for transmission");
} else {
Serial.println("Failed to queue message for transmission");
}
delay(1000);
}
Download the code to another board. The board sends one data frame every second. Connect the board's CAN Bus to a USB CAN analyzer.
The USB CAN analyzer receives the data sent by the board as shown in the figure below.

Was this article helpful?
