我正在开发一个基于ESP32处理器和Arduino框架的项目,该项目通过CANBUS协议与另一块板进行通信。
比特率为 125k,所以大概是“快”。
我正在使用 Sandeep Mistry 库或也称为 adafruit_CAN,它与 Texas Instruments SN65HVD230 CAN 收发器兼容。
我使用 freeRTOS 作为一种方法,该方法将接收每个套接字的帧,并将它们写入板。
然后库本身提供附加到 ISR 的回调来接收响应。
这就是我的问题开始的地方,如果我每秒发送一帧,一切都很棒,但是当我开始每 200 毫秒发送一次时,我可以看到(使用从电脑连接到总线的 CAN 分析器)帧正在到达,他们正在卡上接收并且正在应答,但我的收发器没有触发回调。
我尝试忘记回调并使用另一种 RTOS 方法进行读取,结果相同。
此方法正在迭代任务,如果向量包含 CAN_message_t 对象,则将其写入 CAN,这可以正常工作。
void vTaskCANBUSWriteLoop(void *p)
{
Serial.print("Writer Task");
for (;;)
{
if (!my_global_vector.empty() )
{
response_broker_t myObject = my_global_vector.front();
my_global_vector.pop();
writePlot(myObject);
}
vTaskDelay(200 / portTICK_PERIOD_MS);
}
}
另一种方法是根据文档,如果程序不超过每秒发送一次,则效果很好,如果超过,程序将继续写入,但不会触发回调。 检查它是否与 id 匹配,在解析器中我看到这个 id 就是要输入的 id。
void canCallback(int packetSize)
{
static uint32_t lastTime = 0;
if (can_reader.packetId() == BOARD_ANSWER1 || can_reader.packetId() == BOARD_ANSWER2)
{
if (packetSize)
{
uint8_t buf[8];
while (can_reader.available())
{
CAN.readBytes(buf, sizeof(buf));
}
uint8_tArrayToHexString2(buf, sizeof(buf), rapidResponse);
}
}
}
这是我用来转换为十六进制字符串的方法,它不相关,但可能会带来更多清晰度
void uint8_tArrayToHexString2(uint8_t *data, size_t len, char *output)
{
static const char hexChars[] = "0123456789ABCDEF";
for (size_t i = 0; i < len; ++i)
{
output[i * 3] = hexChars[(data[i] >> 4) & 0xF];
output[i * 3 + 1] = hexChars[data[i] & 0xF];
output[i * 3 + 2] = ' ';
}
output[len * 3 - 1] = '\0';
}
虽然 Adafruit 库很棒,但问题在于它的使用。当你在公交车上快速拍摄很多消息时,公交车最终会变得不稳定。
我用过ESP32的IDF CAN库,和它没什么关系,就像黑夜和白天一样。
我为 Arduino 框架留下了一个最小的实现,以防它对某人有帮助。
#include <Arduino.h>
#include "driver/gpio.h"
#include "driver/can.h"
TaskHandle_t can_receive_task_handle;
void can_receive_task(void *arg)
{
can_message_t rx_msg;
for(;;)
{
if (can_receive(&rx_msg, pdMS_TO_TICKS(100)) == ESP_OK)
{
printf("Received message: ID = 0x%08X, Data: ", rx_msg.identifier);
for (int i = 0; i < rx_msg.data_length_code; i++)
{
printf("%02X ", rx_msg.data[i]);
}
printf("\n");
}
}
}
void setup()
{
Serial.begin(115200);
//? Configure GPIO pins for CAN must be 4/5 or 16/17
gpio_install_isr_service(0);
gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
gpio_set_direction(GPIO_NUM_16, GPIO_MODE_INPUT);
//! Configure CAN controller
can_general_config_t can_config = {
.mode = CAN_MODE_NORMAL,
.tx_io = GPIO_NUM_17,
.rx_io = GPIO_NUM_16,
.clkout_io = GPIO_NUM_NC,
.bus_off_io = GPIO_NUM_NC,
.tx_queue_len = 5,
.rx_queue_len = 5,
.alerts_enabled = CAN_ALERT_NONE,
.clkout_divider = 0};
can_timing_config_t timing_config = CAN_TIMING_CONFIG_125KBITS();
can_filter_config_t filter_config = CAN_FILTER_CONFIG_ACCEPT_ALL();
if (can_driver_install(&can_config, &timing_config, &filter_config) == ESP_OK &&
can_start() == ESP_OK)
{
Serial.println("CAN controller initialized successfully");
}
else
{
Serial.println("Error initializing CAN controller");
return;
}
//! Create RTOS task for receiving CAN messages
xTaskCreate(can_receive_task, "can_receive_task", 2048, NULL, 5, &can_receive_task_handle);
}
void loop()
{
}
特别感谢ESP32 Arduino论坛:使用官方CAN驱动。
我正在我的大学开发一个与此相关的学位项目!我想问你一些关于这方面的问题。我正在使用 esp32 wrover e,但我还没有看到任何使用此型号 esp32 的 CAN 控制器的示例,您认为它有效吗?我可以使用哪些引脚来使用 CAN 控制器?