精通 ESP32 CAN Bus | 完整的發送與接收數據指南
在現代嵌入式系統中,CAN (Controller Area Network) Bus 是一種非常重要的通訊協定,尤其在汽車電子和工業控制領域。本文將詳細介紹如何使用 ESP32 和 ESP-IDF 框架開發 CAN 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 |
+---------+ +---------+ +---------+
開發環境
在開始編程之前,請確保已完成以下準備工作:
- 安裝 ESP-IDF 開發環境 (至少版本 v4.4 或更高)。
- ESP32 開發板。
- CAN 收發器模組 (例如 MCP2551 或 SN65HVD230)。
- CAN 設備或模擬器以進行測試 (可選)。
與 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]: 0x00
,Data[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)、強大的錯誤檢測和自動重傳機制,並能在惡劣的電磁環境中保持穩定,因此在需要高可靠性和即時性的複雜系統中扮演著不可或缺的角色,代表了現代通訊技術的一個重要里程碑。