ESP32-C3 CAN接口的使用指南

esp32-C3 CAN接口使用

  • 功能概述
  • CAN协议关注点
  • 接收过滤器
  • 单过滤器模式
  • 双过滤器模式
  • 关键函数说明
  • 配置和安装驱动
  • 获取TWAI状态信息
  • 发送/接收消息
  • 使用示例
  • CAN控制器自回环测试
  • CAN收发带过滤测试
  • 功能概述

    ESP32-C3具有1个CAN控制器支持以下特性:

  • 兼容ISO 11898-1协议(CAN2.0)
  • 支持标准帧(11bit ID)和扩展帧(29bit ID)格式
  • Bit速率从1Kbit/s-1Mbit/s
  • 工作模式:
  • 正常模式
  • 只听模式(不影响总线)
  • 无响应模式(传输期间无需ACK,可方便自检)
  • 64Byte大小的接收BUF
  • 支持接收单/双过滤
  • 支持错误处理
  • CAN协议关注点

    数据帧或远程帧通过仲裁域抢占CAN总线,协议开始为11bit的ID号,其高位在前低位在后,0表示显性位,1表示隐性位,当多个设备同时发送消息时,ID中的显性位0会覆盖隐性位1,因此ID号越小的设备优先级约高,会优先抢占总线。

    比如ID为3、2、1的设备优先级从高到底为:1(0001B)、2(0010B)、3(0011)。
    SSR:一直为1(隐性)
    RTR:0(显性)-数据帧 1(隐性)-远程帧
    IDE:0(显性)-标准帧 1(隐性)-扩展帧
    ACK:发送端输出1(隐性),接收端响应0(显性),发送端到响应0(显性),则发送表示成功。
    参考文章:https://blog.csdn.net/qq_38880380/article/details/84573821 讲的更加详细。

    接收过滤器

    ESP32-c3接收过滤器如下图所示,配置包含1个验证代码寄存器和1个验证掩码寄存器,分别为32bit。

    基本过滤原理是: 过滤出与验证代码相同的消息,但不关注验证掩码为1的消息bit位。
    例如验证标准帧11位ID:
    验证代码: 000 0001 1010
    验证掩码: 000 0000 0011
    最终过滤: 000 0000 10xx (ID最低2位掩码为1,不关注,只要ID其他位与验证代码相同即可接收)

    单过滤器模式

    单过滤器模式可过滤:

  • 标准帧的11位ID、RTR位、数据字节1和数据字节2
  • 或扩展帧的29位ID和RTR位
  • 双过滤器模式

    双过滤器模式可过滤:

  • 标准帧的11位ID、RTR位、数据字节1(仅filter1)
  • 或扩展帧29位ID中的高16位
  • 关键函数说明

    配置CONFIG_TWAI_ISR_IN_IRAM,并在安装TWAI驱动时设置标志TWAI_ALERT_AND_LOG ,可放置TWAI中断服务程序在内部RAM中。

    配置和安装驱动

    #include "driver/twai.h"
    
    //安装CAN驱动
    esp_err_t twai_driver_install(
    		const twai_general_config_t *g_config, //基本配置
    		const twai_timing_config_t *t_config, //时序配置
    		const twai_filter_config_t *f_config)//过滤器配置
    //启动CAN驱动
    esp_err_t twai_start(void)
    //停用CAN驱动
    esp_err_t twai_stop(void)
    //卸载CAN驱动
    esp_err_t twai_driver_uninstall(void)
    

    结构体说明:

    //CAN接口基本配置
    twai_general_config_t g_config = {
    		.mode = TWAI_MODE_NORMAL , //TWAI_MODE_NORMAL / TWAI_MODE_NO_ACK / TWAI_MODE_LISTEN_ONLY
    		.tx_io = 2, //IO号
    		.rx_io = 3, //IO号
            .clkout_io = TWAI_IO_UNUSED, //io号,不用为-1
            .bus_off_io = TWAI_IO_UNUSED,//io号,不用为-1
            .tx_queue_len = 5, //发送队列长度,0-禁用发送队列
            .rx_queue_len = 5,//接收队列长度
            .alerts_enabled = TWAI_ALERT_NONE,  //警告标志 TWAI_ALERT_ALL 可开启所有警告
            .clkout_divider = 0,//1 to 14 , 0-不用
            .intr_flags = ESP_INTR_FLAG_LEVEL1}//中断优先级
            
    //CAN接口时序配置官方提供了1K to 1Mbps的常用配置
    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); //TWAI_TIMING_CONFIG_500KBITS()
    
    //过滤器配置
    twai_filter_config_t f_config = {
    		.acceptance_code = 0, //验证代码
    		.acceptance_mask = 0xFFFFFFFF, //验证掩码 0xFFFFFFFF表示全部接收
    		.single_filter = true}//true:单过滤器模式 false:双过滤器模式
    

    获取TWAI状态信息

    //获取twai状态
    esp_err_t twai_get_status_info(twai_status_info_t *status_info)
    //返回值:ESP_OK: 成功;ESP_ERR_INVALID_ARG: 参数无效;ESP_ERR_INVALID_STATE:驱动未安装
    
    //状态信息
    twai_status_info_t status_info={
    		.state=,//TWAI_STATE_STOPPED / TWAI_STATE_RUNNING / TWAI_STATE_BUS_OFF / TWAI_STATE_RECOVERING
    		.msgs_to_tx=,//发送队列消息数       
    		.msgs_to_rx=,//接收队列消息数    
    		.tx_error_counter=, //发送错误计数
    		.rx_error_counter=, //接收错误计数
    		.tx_failed_count=,  //发送失败计数
    		.rx_missed_count=,  //因接收队列满丢失的消息数
    		.rx_overrun_count=, //因接收buf(64Byte)满而丢失的消息数
    		.arb_lost_count=,   //仲裁失败计数
    		.bus_error_count=};//总线错误计数
    

    发送/接收消息

    //发送消息到发送队列排队,如发送队列为空则立即发送,为满则等待ticks_to_wait时间
    esp_err_t twai_transmit(
    		const twai_message_t *message, //消息包
    		TickType_t ticks_to_wait)//超时时间
    /***********************************************
    * 	返回值:
    *	ESP_OK:发送成功
    *	ESP_ERR_INVALID_ARG:参数无效
    *	ESP_ERR_TIMEOUT:等待TX队列时超时
    *	ESP_FAIL:TX队列已禁用,且当前正在传输另一条消息
    *	ESP_ERR_INVALID_STATE:CAN驱动程序未运行或未安装
    *	ESP_ERR_NOT_SUPPORTED:只听模式不支持发送
    *************************************************/
    
    //从接收队列接收1个消息,若队列为空,则阻塞
    esp_err_t twai_receive(
    		twai_message_t *message, //消息包
    		TickType_t ticks_to_wait)//超时
    /***********************************************
    * 	返回值:
    *	ESP_OK:接收成功
    *	ESP_ERR_INVALID_ARG:参数无效
    *	ESP_ERR_TIMEOUT:等待队列时超时
    *	ESP_FAIL:TX队列已禁用,且当前正在传输另一条消息
    *	ESP_ERR_INVALID_STATE:CAN驱动程序未运行或未安装
    *	ESP_ERR_NOT_SUPPORTED:只听模式不支持发送
    *************************************************/
    
    
    //发送/接收消息帧结构
    twai_message_t send_message1 = {
    		.extd = 1,//0-标准帧; 1-扩展帧
    		.rtr = 0,//0-数据帧; 1-远程帧
    		.ss = 1, //0-错误重发; 1-单次发送(仲裁或丢失时消息不会被重发),对接收消息无效
    		.self = 0,//0-不接收自己发送的消息,1-接收自己发送的消息,对接收消息无效
    		.dlc_non_comp = 0,// 0-数据长度不大于8(ISO 11898-1); 1-数据长度大于8(非标);
    		.identifier = ID0, //11/29位ID
    		.data_length_code = 0, //DLC数据长度4bit位宽
    		.data = {0, 0 , 0 , 0 ,0 ,0 ,0 ,0}};//发送数据,对远程帧无效
    

    使用示例

    CAN控制器自回环测试

    硬件需将2-3脚回环或连接CAN接口转换芯片,程序运行10s,分别发送标准帧、远程帧、扩展帧,并接收打印帧内容。
    需注意自回环测试需要配置:twai_general_config_t->mode = TWAI_MODE_NO_ACK;twai_message_t ->self = 1;

    #include <stdio.h>
    #include <stdlib.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "freertos/semphr.h"
    #include "esp_err.h"
    #include "esp_log.h"
    #include "driver/twai.h"
    
    #define EXAMPLE_TAG "TWAI Self Test"
    #define SENDMSG 0
    #define RECEIVEMSG 1
    /* --------------------------- Tasks and Functions -------------------------- */
    
    void printf_msg(int flag, twai_message_t *msg) // flag:0-send 1-receive
    {
        int j;
        if (flag)
            printf("Receive: ");
        else
            printf("Send   : ");
        if (msg->extd)
            printf("Extended ");
        else
            printf("Standard ");
        if (msg->rtr)
            printf("Remote Frame, ");
        else
            printf("Data  Frame,  ");
        printf("ID: %d    ", msg->identifier);
        if (msg->rtr == 0)
        {
            for (j = 0; j < msg->data_length_code; j++)
            {
                printf("D%d: %d\t", j, msg->data[j]);
            }
            printf("\n");
        }
        else
            printf("\n");
    }
    
    static void twai_transmit_task(void *arg)
    {
        int i;
        twai_message_t s1 = {
            .extd = 0,                         // 0-标准帧; 1-扩展帧
            .rtr = 0,                          // 0-数据帧; 1-远程帧
            .ss = 1,                           // 0-错误重发; 1-单次发送(仲裁或丢失时消息不会被重发),对接收消息无效
            .self = 1,                         // 0-不接收自己发送的消息,1-接收自己发送的消息,对接收消息无效
            .dlc_non_comp = 0,                 // 0-数据长度不大于8(ISO 11898-1); 1-数据长度大于8(非标);
            .identifier = 60,                  // 11/29位ID
            .data_length_code = 4,             // DLC数据长度4bit位宽
            .data = {0, 0, 0, 0, 0, 0, 0, 0}}; //发送数据,对远程帧无效
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 3; i++) //发送3个标准数据帧
        {
            s1.data[0] = i;
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.rtr = 1;
        s1.data_length_code = 6;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 1; i++) //发送1个标准远程帧
        {
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.extd = 1;
        s1.rtr = 0;
        s1.data_length_code = 5;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 3; i++) //发送3个扩展数据帧
        {
            s1.data[0] = i;
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.rtr = 1;
        s1.data_length_code = 3;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 1; i++) //发送1个扩展远程帧
        {
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        vTaskDelete(NULL);
    }
    
    static void twai_receive_task(void *arg)
    {
        twai_message_t r1;
        for (int i = 0; i < 8; i++) //发送1个扩展远程帧
        {
            ESP_ERROR_CHECK(twai_receive(&r1, portMAX_DELAY));
            printf_msg(RECEIVEMSG, &r1);
        }
        vTaskDelete(NULL);
    }
    
    void app_main(void)
    {
        // CAN接口基本配置
        twai_general_config_t g_config = {
            .mode = TWAI_MODE_NO_ACK,            // TWAI_MODE_NORMAL / TWAI_MODE_NO_ACK / TWAI_MODE_LISTEN_ONLY
            .tx_io = 2,                          // IO号
            .rx_io = 3,                          // IO号
            .clkout_io = TWAI_IO_UNUSED,         // io号,不用为-1
            .bus_off_io = TWAI_IO_UNUSED,        // io号,不用为-1
            .tx_queue_len = 5,                   //发送队列长度,0-禁用发送队列
            .rx_queue_len = 5,                   //接收队列长度
            .alerts_enabled = TWAI_ALERT_NONE,   //警告标志 TWAI_ALERT_ALL 可开启所有警告
            .clkout_divider = 0,                 // 1 to 14 , 0-不用
            .intr_flags = ESP_INTR_FLAG_LEVEL1}; //中断优先级
    
        // CAN接口时序配置官方提供了1K to 1Mbps的常用配置
        twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); // TWAI_TIMING_CONFIG_500KBITS()
    
        //过滤器配置
        twai_filter_config_t f_config = {
            .acceptance_code = 0,          //验证代码
            .acceptance_mask = 0xFFFFFFFF, //验证掩码 0xFFFFFFFF表示全部接收
            .single_filter = true};        // true:单过滤器模式 false:双过滤器模式
    
        ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
        ESP_LOGI(EXAMPLE_TAG, "Driver installed");
        ESP_ERROR_CHECK(twai_start());
        ESP_LOGI(EXAMPLE_TAG, "Driver started");
    
        xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, 8, NULL, tskNO_AFFINITY);
        xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, 9, NULL, tskNO_AFFINITY);
    
        vTaskDelay(pdMS_TO_TICKS(10000)); //运行10s
    
        twai_status_info_t status_info;
        twai_get_status_info(&status_info);
        while (status_info.msgs_to_tx != 0)
        {
            ESP_ERROR_CHECK(twai_get_status_info(&status_info));
        }
        ESP_ERROR_CHECK(twai_stop()); // Stop the TWAI Driver
        ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
        ESP_ERROR_CHECK(twai_driver_uninstall());
        ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
    }
    
    

    效果:

    I (278) TWAI Self Test: Driver installed
    I (278) TWAI Self Test: Driver started
    Send : Standard Data Frame, ID: 60 D0: 0 D1: 0 D2: 0 D3: 0
    Send : Standard Data Frame, ID: 60 D0: 1 D1: 0 D2: 0 D3: 0
    Send : Standard Data Frame, ID: 60 D0: 2 D1: 0 D2: 0 D3: 0
    Receive: Standard Data Frame, ID: 60 D0: 0 D1: 0 D2: 0 D3: 0
    Receive: Standard Data Frame, ID: 60 D0: 1 D1: 0 D2: 0 D3: 0
    Receive: Standard Data Frame, ID: 60 D0: 2 D1: 0 D2: 0 D3: 0
    Send : Standard Remote Frame, ID: 60
    Receive: Standard Remote Frame, ID: 60
    Send : Extended Data Frame, ID: 60 D0: 0 D1: 0 D2: 0 D3: 0 D4: 0
    Send : Extended Data Frame, ID: 60 D0: 1 D1: 0 D2: 0 D3: 0 D4: 0
    Send : Extended Data Frame, ID: 60 D0: 2 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 60 D0: 0 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 60 D0: 1 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 60 D0: 2 D1: 0 D2: 0 D3: 0 D4: 0
    Send : Extended Remote Frame, ID: 60
    Receive: Extended Remote Frame, ID: 60
    I (10278) TWAI Self Test: Driver stopped
    I (10278) TWAI Self Test: Driver uninstalled

    CAN收发带过滤测试

    收发测试至少有2个CAN终端,本次测试采用ESP32-C3作为master,ESP32作为slave,master分别发送ID号为0x55b和0x55e的消息包,slave设置过滤器,只接收ID为0x55e的扩展帧,并将数据做处理后以0xcc的ID发送到主机。
    需要注意的是,正常收发数据需配置: twai_general_config_t->.mode = TWAI_MODE_NORMAL; 和 twai_message_t->self = 0; 另外使用过滤器注意移位。

    主机代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "freertos/semphr.h"
    #include "esp_err.h"
    #include "esp_log.h"
    #include "driver/twai.h"
    
    #define EXAMPLE_TAG "TWAI master"
    #define SENDMSG 0
    #define RECEIVEMSG 1
    /* --------------------------- Tasks and Functions -------------------------- */
    
    void printf_msg(int flag, twai_message_t *msg) // flag:0-send 1-receive
    {
        int j;
        if (flag)
            printf("Receive: ");
        else
            printf("Send   : ");
        if (msg->extd)
            printf("Extended ");
        else
            printf("Standard ");
        if (msg->rtr)
            printf("Remote Frame, ");
        else
            printf("Data  Frame,  ");
        printf("ID: 0x%x    ", msg->identifier);
        if (msg->rtr == 0)
        {
            for (j = 0; j < msg->data_length_code; j++)
            {
                printf("D%d: %d\t", j, msg->data[j]);
            }
            printf("\n");
        }
        else
            printf("\n");
    }
    
    static void twai_transmit_task(void *arg)
    {
        int i;
        twai_message_t s1 = {
            .extd = 0,                         // 0-标准帧; 1-扩展帧
            .rtr = 0,                          // 0-数据帧; 1-远程帧
            .ss = 1,                           // 0-错误重发; 1-单次发送(仲裁或丢失时消息不会被重发),对接收消息无效
            .self = 0,                         // 0-不接收自己发送的消息,1-接收自己发送的消息,对接收消息无效
            .dlc_non_comp = 0,                 // 0-数据长度不大于8(ISO 11898-1); 1-数据长度大于8(非标);
            .identifier = 0x55b,                  // 11/29位ID
            .data_length_code = 4,             // DLC数据长度4bit位宽
            .data = {0, 0, 0, 0, 0, 0, 0, 0}}; //发送数据,对远程帧无效
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 3; i++) //发送3个标准数据帧
        {
            s1.data[0] = i;
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.rtr = 1;
        s1.data_length_code = 6;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 1; i++) //发送1个标准远程帧
        {
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.extd = 1;
        s1.rtr = 0;
        s1.identifier = 0x55e;
        s1.data_length_code = 5;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 3; i++) //发送3个扩展数据帧
        {
            s1.data[0] = i;
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        s1.rtr = 1;
        s1.data_length_code = 3;
        vTaskDelay(pdMS_TO_TICKS(1000));
        for (i = 0; i < 1; i++) //发送1个扩展远程帧
        {
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
            printf_msg(SENDMSG, &s1);
        }
    
        vTaskDelete(NULL);
    }
    
    static void twai_receive_task(void *arg)
    {
        twai_message_t r1;
        for (int i = 0; i < 8; i++) //发送1个扩展远程帧
        {
            ESP_ERROR_CHECK(twai_receive(&r1, portMAX_DELAY));
            printf_msg(RECEIVEMSG, &r1);
        }
        vTaskDelete(NULL);
    }
    
    void app_main(void)
    {
        // CAN接口基本配置
        twai_general_config_t g_config = {
            .mode = TWAI_MODE_NORMAL,            // TWAI_MODE_NORMAL / TWAI_MODE_NO_ACK / TWAI_MODE_LISTEN_ONLY
            .tx_io = 2,                          // IO号
            .rx_io = 3,                          // IO号
            .clkout_io = TWAI_IO_UNUSED,         // io号,不用为-1
            .bus_off_io = TWAI_IO_UNUSED,        // io号,不用为-1
            .tx_queue_len = 5,                   //发送队列长度,0-禁用发送队列
            .rx_queue_len = 5,                   //接收队列长度
            .alerts_enabled = TWAI_ALERT_NONE,   //警告标志 TWAI_ALERT_ALL 可开启所有警告
            .clkout_divider = 0,                 // 1 to 14 , 0-不用
            .intr_flags = ESP_INTR_FLAG_LEVEL1}; //中断优先级
    
        // CAN接口时序配置官方提供了1K to 1Mbps的常用配置
        twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); // TWAI_TIMING_CONFIG_500KBITS()
    
        //过滤器配置
        twai_filter_config_t f_config = {
            .acceptance_code = 0,          //验证代码
            .acceptance_mask = 0xFFFFFFFF, //验证掩码 0xFFFFFFFF表示全部接收
            .single_filter = true};        // true:单过滤器模式 false:双过滤器模式
    
        ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
        ESP_LOGI(EXAMPLE_TAG, "Driver installed");
        ESP_ERROR_CHECK(twai_start());
        ESP_LOGI(EXAMPLE_TAG, "Driver started");
    
        xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, 8, NULL, tskNO_AFFINITY);
        xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, 9, NULL, tskNO_AFFINITY);
    
        vTaskDelay(pdMS_TO_TICKS(10000)); //运行10s
    
        twai_status_info_t status_info;
        twai_get_status_info(&status_info);
        while (status_info.msgs_to_tx != 0)
        {
            ESP_ERROR_CHECK(twai_get_status_info(&status_info));
        }
        ESP_ERROR_CHECK(twai_stop()); // Stop the TWAI Driver
        ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
        ESP_ERROR_CHECK(twai_driver_uninstall());
        ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
    }
    
    

    从机代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "freertos/semphr.h"
    #include "esp_err.h"
    #include "esp_log.h"
    #include "driver/twai.h"
    
    #define EXAMPLE_TAG "TWAI slave"
    #define SENDMSG 0
    #define RECEIVEMSG 1
    /* --------------------------- Tasks and Functions -------------------------- */
    
    void printf_msg(int flag, twai_message_t *msg) // flag:0-send 1-receive
    {
        int j;
        if (flag)
            printf("Receive: ");
        else
            printf("Send   : ");
        if (msg->extd)
            printf("Extended ");
        else
            printf("Standard ");
        if (msg->rtr)
            printf("Remote Frame, ");
        else
            printf("Data  Frame,  ");
        printf("ID: 0x%x    ", msg->identifier);
        if (msg->rtr == 0)
        {
            for (j = 0; j < msg->data_length_code; j++)
            {
                printf("D%d: %d\t", j, msg->data[j]);
            }
            printf("\n");
        }
        else
            printf("\n");
    }
    
    static void twai_receive_task(void *arg)
    {
        int j;
        twai_message_t s1 = {
            .extd = 0,                         // 0-标准帧; 1-扩展帧
            .rtr = 0,                          // 0-数据帧; 1-远程帧
            .ss = 1,                           // 0-错误重发; 1-单次发送(仲裁或丢失时消息不会被重发),对接收消息无效
            .self = 0,                         // 0-不接收自己发送的消息,1-接收自己发送的消息,对接收消息无效
            .dlc_non_comp = 0,                 // 0-数据长度不大于8(ISO 11898-1); 1-数据长度大于8(非标);
            .identifier = 0xcc,                 // 11/29位ID
            .data_length_code = 4,             // DLC数据长度4bit位宽
            .data = {0, 0, 0, 0, 0, 0, 0, 0}}; //发送数据,对远程帧无效
        twai_message_t r1;
        for (int i = 0; i < 8; i++)
        {
            ESP_ERROR_CHECK(twai_receive(&r1, portMAX_DELAY));
            printf_msg(RECEIVEMSG, &r1);
            s1.extd = r1.extd;
            s1.rtr = r1.rtr;
            s1.data_length_code = r1.data_length_code;
            if (r1.rtr == 0)
            {
                for (j = 0; j < r1.data_length_code; j++)
                    s1.data[j] = 255 - r1.data[j]; // 255减去原始数据回传
            }
            ESP_ERROR_CHECK(twai_transmit(&s1, portMAX_DELAY));
        }
        vTaskDelete(NULL);
    }
    
    void app_main(void)
    {
        // CAN接口基本配置
        twai_general_config_t g_config = {
            .mode = TWAI_MODE_NORMAL,            // TWAI_MODE_NORMAL / TWAI_MODE_NO_ACK / TWAI_MODE_LISTEN_ONLY
            .tx_io = 21,                          // IO号
            .rx_io = 22,                          // IO号
            .clkout_io = TWAI_IO_UNUSED,         // io号,不用为-1
            .bus_off_io = TWAI_IO_UNUSED,        // io号,不用为-1
            .tx_queue_len = 5,                   //发送队列长度,0-禁用发送队列
            .rx_queue_len = 5,                   //接收队列长度
            .alerts_enabled = TWAI_ALERT_NONE,   //警告标志 TWAI_ALERT_ALL 可开启所有警告
            .clkout_divider = 0,                 // 1 to 14 , 0-不用
            .intr_flags = ESP_INTR_FLAG_LEVEL1}; //中断优先级
    
        // CAN接口时序配置官方提供了1K to 1Mbps的常用配置
        twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); // TWAI_TIMING_CONFIG_500KBITS()
    
        //过滤器配置
        twai_filter_config_t f_config = {
            .acceptance_code = 0x55e << 3, //验证代码
            .acceptance_mask = 0x00000007, //验证掩码 0xFFFFFFFF表示全部接收 7:不关注低3bit
            .single_filter = true};        // true:单过滤器模式 false:双过滤器模式
    
        ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
        ESP_LOGI(EXAMPLE_TAG, "Driver installed");
        ESP_ERROR_CHECK(twai_start());
        ESP_LOGI(EXAMPLE_TAG, "Driver started");
    
        xTaskCreatePinnedToCore(twai_receive_task, "TWAI_rx", 4096, NULL, 8, NULL, tskNO_AFFINITY);
    }
    
    

    效果:
    主机打印:

    I (277) TWAI master: Driver installed
    I (277) TWAI master: Driver started
    Send : Standard Data Frame, ID: 0x55b D0: 0 D1: 0 D2: 0 D3: 0
    Send : Standard Data Frame, ID: 0x55b D0: 1 D1: 0 D2: 0 D3: 0
    Send : Standard Data Frame, ID: 0x55b D0: 2 D1: 0 D2: 0 D3: 0
    Send : Standard Remote Frame, ID: 0x55b
    Send : Extended Data Frame, ID: 0x55e D0: 0 D1: 0 D2: 0 D3: 0 D4: 0
    Send : Extended Data Frame, ID: 0x55e D0: 1 D1: 0 D2: 0 D3: 0 D4: 0
    Send : Extended Data Frame, ID: 0x55e D0: 2 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 0xcc D0: 255 D1: 255 D2: 255 D3: 255 D4: 255
    Receive: Extended Data Frame, ID: 0xcc D0: 254 D1: 255 D2: 255 D3: 255 D4: 255
    Receive: Extended Data Frame, ID: 0xcc D0: 253 D1: 255 D2: 255 D3: 255 D4: 255
    Send : Extended Remote Frame, ID: 0x55e
    Receive: Extended Remote Frame, ID: 0xcc
    I (10277) TWAI master: Driver stopped
    I (10277) TWAI master: Driver uninstalled

    从机打印:

    I (308) TWAI slave: Driver installed
    I (308) TWAI slave: Driver started
    Receive: Extended Data Frame, ID: 0x55e D0: 0 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 0x55e D0: 1 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Data Frame, ID: 0x55e D0: 2 D1: 0 D2: 0 D3: 0 D4: 0
    Receive: Extended Remote Frame, ID: 0x55e

    可见从机只响应了ID为0x55e的扩展帧。

    物联沃分享整理
    物联沃-IOTWORD物联网 » ESP32-C3 CAN接口的使用指南

    发表评论