精通 ESP32 CAN Bus | 完整的發送與接收數據指南


在現代嵌入式系統中,CAN (Controller Area Network) Bus 是一種非常重要的通訊協定,尤其在汽車電子和工業控制領域。本文將詳細介紹如何使用 ESP32 和 ESP-IDF 框架開發 CAN Bus (匯流排) 驅動程式。

CAM Bus

簡介

在 ESP32 中,CAN 通信由 TWAI (Two-Wire Automotive Interface) 硬體模塊驅動,完全兼容 CAN 2.0 協議標準。這使得 ESP32 不僅可以參與 CAN Bus 網路中的數據交換,還能憑藉其內建的處理能力,充當網關、數據記錄器或節點控制器等角色。此外,ESP32 的靈活性允許開發者結合 CAN 與 Wi-Fi 或藍牙,實現遠程監控與診斷等高級功能。

什麼是 CAN Bus?

CAN Bus (Controller Area Network Bus) 是一種高效的串行通訊協議,最初由 Bosch 在 1980 年代為汽車應用設計,現在廣泛應用於多個領域,包括工業自動化、機器人、醫療設備和家居自動化。

CAN Bus 的特性

  • 多主架構: 支援多個設備互聯,任何節點都可發起通信。
  • 高可靠性: 內建錯誤檢測和容錯功能,數據傳輸穩定。
  • 差分信號: 使用 CANH 和 CANL,抗干擾能力強。
  • 優先級機制: 高優先級數據先被傳輸。
  • 支援多節點: 最多連接 120 個設備。
  • 缺點 : 波特率有限、數據負載較小(最多只能傳輸 8 字節的數據)、硬體需求相對較高。

以下是使用中文的 CAN 總線接線圖,並說明每個設備都擁有各自的 CAN 收發器模組(例如:SN65HVD230)的情況。

      +--------+           +--------+           +--------+
      | CAN    |           | CAN    |           | CAN    |
      | Device |           | Device |           | Device |
      | (e.g., |           | (e.g., |           | (e.g., |
      | ESP32) |           | Sensor)|           | MCU)   |
      +--------+           +--------+           +--------+
           |                   |                   |
     +---------+          +---------+          +---------+
     | CAN_H   |----------| CAN_H   |----------| CAN_H   |
     +---------+          +---------+          +---------+
           |                   |                   |
     +---------+          +---------+          +---------+
     | CAN_L   |----------| CAN_L   |----------| CAN_L   |
     +---------+          +---------+          +---------+

開發環境

在開始編程之前,請確保已完成以下準備工作:

與 SN65HVD230 的接線圖

以下是用 ASCII 碼繪製的接線圖:

+------------+          +-------------------+         +---------+
|   ESP32    |          | SN65HVD230 (CAN)  |         |   CAN   |
|            |          |                   |         | Device  |
|   GPIO4 ---+--------->| TXD               |         |         |
|   GPIO5 ---+--------->| RXD               |         |         |
|    GND  ---+--------->| GND               |         |         |
|    3V3  ---+--------->| VCC               |         |         |
|            |          | CANH --- CAN Bus  |---------|  CANH   |
|            |          | CANL --- CAN Bus  |---------|  CANL   |
+------------+          +-------------------+         +---------+

ESP32 和 SN65HVD230 的信號連接:

  • ESP32 的 GPIO4 → SN65HVD230 的 TXD (資料傳輸)
  • ESP32 的 GPIO5 → SN65HVD230 的 RXD (資料接收)
  • 確保 ESP32 和其他 CAN 匯流排節點的波特率一致,否則無法正常通信。

電源與地線:

  • ESP32 的 3V3 → SN65HVD230 的 VCC (供電)
  • ESP32 的 GND → SN65HVD230 的 GND (接地)
  • ESP32 使用 3.3V,SN65HVD230 的 VCC 必須接 3.3V 以避免燒毀設備。

CANH 和 CANL:

  • SN65HVD230 的 CANH → 連接到 CAN Bus 的高電平 (CAN High)。
  • SN65HVD230 的 CANL → 連接到 CAN Bus 的低電平 (CAN Low)。
  • 如果 CAN 網路需要終端電阻,請在 CANH 和 CANL 之間接兩端接上 120Ω 電阻,以確保數據傳輸的穩定性。

編寫代碼

ESP-IDF 提供了一個內建的 CAN 驅動程式 (稱為 TWAI 驅動程式)。以下是配置和初始化 TWAI 驅動的步驟:

#include "driver/twai.h"  // Include the TWAI (CAN) driver library
#include "esp_log.h"      // Include ESP logging library

#define TAG "CAN_DRIVER"  // Define a tag for logging messages

void app_main() {
    // Configure the CAN driver parameters
    twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL);
    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    // Initialize the CAN driver
    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
        ESP_LOGI(TAG, "TWAI driver installed successfully");
    } else {
        ESP_LOGE(TAG, "Failed to install TWAI driver");
        return; // Exit the function if driver installation fails
    }

    // Start the CAN driver
    if (twai_start() == ESP_OK) {
        ESP_LOGI(TAG, "TWAI driver started successfully");
    } else {
        ESP_LOGE(TAG, "Failed to start TWAI driver");
        return; // Exit the function if driver start fails
    }

    // Prepare a message to send
    twai_message_t tx_message;          
    tx_message.identifier = 0x100;     
    tx_message.data_length_code = 8;   
    for (int i = 0; i < 8; i++) {      
        tx_message.data[i] = i;        
    }

    // Transmit the message
    if (twai_transmit(&tx_message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        ESP_LOGI(TAG, "Message transmitted");
    } else {
        ESP_LOGE(TAG, "Failed to transmit message");
    }

    // Receive a message
    twai_message_t rx_message;  // Declare a message structure for receiving
    if (twai_receive(&rx_message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        ESP_LOGI(TAG, "Message received");
        ESP_LOGI(TAG, "ID: 0x%x, DLC: %d, Data:", rx_message.identifier, rx_message.data_length_code);
        for (int i = 0; i < rx_message.data_length_code; i++) {
            ESP_LOGI(TAG, "Data[%d]: 0x%x", i, rx_message.data[i]);
        }
    } else {
        ESP_LOGE(TAG, "Failed to receive message");
    }

    // Stop and uninstall the CAN driver
    twai_stop();                         
    twai_driver_uninstall();             
    ESP_LOGI(TAG, "TWAI driver uninstalled");
}

代碼解釋

配置參數:

  • TWAI_GENERAL_CONFIG_DEFAULT 用於設置 GPIO 引腳以及工作模式。
  • TWAI_TIMING_CONFIG_500KBITS 設置 CAN 匯流排位速率 (這裡為 500 kbps)。
  • TWAI_FILTER_CONFIG_ACCEPT_ALL 配置接受所有 CAN 消息的過濾器。

初始化與啟動:

  • twai_driver_install 來初始化驅動程式。
  • twai_start 開啟驅動程式。

發送和接收消息:

  • twai_message_t 結構體包含 CAN 消息的 ID、數據長度以及實際數據。
  • twai_transmit 用於發送消息。
  • twai_receive 函數接收來自 CAN 匯流排的訊息

停止與卸載:

  • 停止驅動程式並釋放資源以清理環境。

結果輸出

以下是程式碼執行後在串列監視器(Serial Monitor)上可能看到的輸出模擬結果,假設一切正常運行:

I (10) CAN_DRIVER: TWAI driver installed successfully
I (20) CAN_DRIVER: TWAI driver started successfully
I (30) CAN_DRIVER: Message transmitted
I (40) CAN_DRIVER: Message received
I (40) CAN_DRIVER: ID: 0x100, DLC: 8, Data:
I (40) CAN_DRIVER: Data[0]: 0x0
I (40) CAN_DRIVER: Data[1]: 0x1
I (40) CAN_DRIVER: Data[2]: 0x2
I (40) CAN_DRIVER: Data[3]: 0x3
I (40) CAN_DRIVER: Data[4]: 0x4
I (40) CAN_DRIVER: Data[5]: 0x5
I (40) CAN_DRIVER: Data[6]: 0x6
I (40) CAN_DRIVER: Data[7]: 0x7
I (50) CAN_DRIVER: TWAI driver uninstalled
  • TWAI driver installed successfully : 驅動程式已成功初始化,表示 TWAI 硬體和設置未出現問題。
  • TWAI driver started successfully : 驅動程式已啟動,設備可以發送或接收 CAN 消息。
  • Message transmitted : 消息已成功發送至 CAN 線路。
  • Message received : 表示 ESP32 已成功接收到一條 CAN 消息,這說明發送和接收功能均運作正常。
  • ID: 0x100 : 消息的標識符(此處為標準 ID 0x100)。CAN 系統中通常使用此標識符來區分不同類型的消息,例如診斷消息或數據更新。
  • DLC: 8 : Data Length Code(數據長度代碼),表示消息包含 8 個數據字節。CAN 消息的數據部分最大可為 8 字節。
  • Data: 每個數據字節將逐行列印,表示接收到的有效載荷內容。例如:Data[0]: 0x00Data[1]: 0x01, …, Data[7]: 0x07
  • TWAI driver uninstalled : 驅動程式已停用並被正確卸載,釋放資源。

錯誤情況的可能輸出:

如果某個步驟出現問題,例如驅動程式安裝失敗,您可能會看到:

E (10) CAN_DRIVER: Failed to install TWAI driver

或如果驅動程式無法啟動:

E (20) CAN_DRIVER: Failed to start TWAI driver

結論

CAN Bus 是一種高效、可靠的串列通訊協定,最初由博世公司為汽車工業開發,現已廣泛應用於工業控制、醫療設備和機器人系統等領域。它憑藉其抗干擾、即時通訊和低成本的特點,成為現代電子系統中連接不同設備的關鍵通訊技術。作為一種去中心化的通訊系統,CAN Bus 允許多個設備在同一總線上進行通訊,具有高速度(最高可達1Mbps)、強大的錯誤檢測和自動重傳機制,並能在惡劣的電磁環境中保持穩定,因此在需要高可靠性和即時性的複雜系統中扮演著不可或缺的角色,代表了現代通訊技術的一個重要里程碑。