使用 ESP32 IDF 實現 I2C 掃描
內容
簡介
I2C(Inter-Integrated Circuit) 是一種常見的串行通信協議,用於連接微控制器和各種外設。在 I2C 通訊中,有一個主設備和一個或多個從設備。每個從設備都有一個唯一的 7 位或 10 位地址,主設備通過發送這個地址來選擇要通信的從設備。
工作原理
I2C 掃描器的工作原理是通過嘗試與所有可能的 I2C 地址進行通信,來識別 BUS 上存在的從設備。具體而言,主設備會嘗試對每個可能的地址發送「開始條件」和「停止條件」,並檢查從設備是否應答。如果從設備應答,則表示該地址上存在一個設備。
安裝 VSCode 和 ESP-IDF VSCode 擴展
確保你已經安裝和配置好了 ESP-IDF 開發環境。您也可以參考 ESP32 入門到精通 – 在 VSCode 安裝 ESP-IDF 插件 這篇文章。
新建 ESP32 專案
利用在 VSCode 的 IDF 插件來新建一個 ESP32 專案可參考 ESP32 入門到精通 – 如何用 VSCode 創建 ESP32 專案。
使用 ESP32 IDF 實作
以下是使用 ESP32 IDF I2C 編寫掃描器程式,如下所示...
#include <stdio.h>
#include "driver/i2c.h"
#include "esp_log.h"
#define I2C_MASTER_SCL_IO 22 // Set SCL pin
#define I2C_MASTER_SDA_IO 21 // Set SDA pin
#define I2C_MASTER_NUM I2C_NUM_0 // Use I2C port 0
#define I2C_MASTER_FREQ_HZ 100000 // Set I2C frequency to 100kHz
#define I2C_MASTER_TX_BUF_DISABLE 0 // Disable TX buffer
#define I2C_MASTER_RX_BUF_DISABLE 0 // Disable RX buffer
static const char *TAG = "i2c_scanner";
void i2c_master_init() {
// Configure I2C master settings
i2c_config_t conf;
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = I2C_MASTER_SDA_IO;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_io_num = I2C_MASTER_SCL_IO;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
conf.clk_flags = 0;
// Apply configuration to the I2C driver
i2c_param_config(I2C_MASTER_NUM, &conf);
// Install I2C driver
i2c_driver_install(I2C_MASTER_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
void i2c_scanner() {
printf("Scanning I2C bus...\n");
// Iterate over all possible I2C addresses
for (int addr = 1; addr < 127; addr++) {
// Create I2C command link
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
// Send I2C address with write bit
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
// Execute I2C command and check for response
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(1000));
i2c_cmd_link_delete(cmd);
// If device responds, print the address
if (ret == ESP_OK) {
printf("Found device at address 0x%02x\n", addr);
}
}
printf("I2C scan complete.\n");
}
void app_main() {
// Initialize I2C master
i2c_master_init();
// Start scanning for I2C devices
i2c_scanner();
}
程式說明
1. i2c_master_init:
這段代碼配置了 I2C 主設備的 SDA 和 SCL 引腳、I2C 時鐘頻率(100kHz),並安裝了 I2C 驅動程式。
i2c_param_config 函數用於設置 I2C 參數。
i2c_driver_install 函數用於安裝 I2C 驅動程式。
2. i2c_scanner:
這段代碼迴圈遍歷所有可能的 I2C 地址(1 到 127)。對於每個地址,主設備會嘗試進行一次 I2C 通信。如果通信成功(即接收到從設備的應答),則表示該地址上存在一個設備。
使用 i2c_cmd_link_create 創建 I2C 命令鏈,並通過 i2c_master_cmd_begin 發送命令。
如果通信成功 (ESP_OK),則會打印出發現的設備地址。
3. 主程序 (app_main):
初始化 I2C 並運行掃描器函數。
編譯和燒錄
在 VSCode 中找到 "ESP32-IDF : Build, Flash and Monitor" ICON 執行和燒錄。
查看結果
若連有連接 I2C 裝置沒有任何問題,我們可以查看在終端機的列印結果,會有如下結果...
Scanning I2C bus...
Found device at address 0x3C
Found device at address 0x68
I2C scan complete.
I2C 掃描器程式說明
當你使用 ESP32 運行這個 I2C 掃描器程式時,會有兩種主要的結果,取決於是否有 I2C 設備連接到 BUS 上。
1. 如果有 I2C 設備連接到 BUS 上
當 I2C BUS 上連接了至少一個設備時,掃描器會嘗試與每個地址進行通信。每當它成功與某個地址通信並收到設備的應答時,它就會輸出該設備的 I2C 地址。輸出結果可能如下所示:
Scanning I2C bus...
Found device at address 0x3C
Found device at address 0x68
I2C scan complete.
Scanning I2C bus...: 表示 I2C 掃描已經開始。
Found device at address 0x3C 和 Found device at address 0x68: 這些行表示在地址 0x3C 和 0x68 分別檢測到了 I2C 設備。每個地址對應一個連接到 BUS 上的 I2C 從設備。
I2C scan complete.: 表示掃描已經完成。
2. 如果沒有 I2C 設備連接到 BUS 上
當 I2C BUS 上沒有連接任何設備時,掃描器仍然會嘗試與每個可能的地址進行通信。但是,由於沒有設備應答,掃描器不會檢測到任何設備地址。輸出結果會如下所示:
Scanning I2C bus...
I2C scan complete.
Scanning I2C bus...: 表示 I2C 掃描已經開始。
I2C scan complete.: 表示掃描已經完成。
問題
在這兩行之間沒有其他輸出,這表示在掃描範圍內的所有地址都沒有檢測到設備。這種情況可能發生在以下幾種情況下:
1. 未連接任何設備: I2C BUS 上沒有任何設備物理連接到 ESP32。
2. 設備的接線問題: I2C 設備的 SDA 或 SCL 線未正確連接,或接線鬆動。
3. 設備的電源問題: I2C 設備未通電或電源不足,導致無法應答 I2C 通信。
4. 地址衝突或配置錯誤: 設備地址設置錯誤或存在地址衝突,導致掃描器無法與設備通信。
5. 設備不支持高頻率: 不同的 I2C 設備有不同的時鐘速度上限。一些設備可能只支持標準模式(100 kHz)或快速模式(400 kHz)。如果主設備的 I2C 時鐘頻率設置得超過了從設備支持的範圍,例如設置為 1 MHz 或更高,從設備可能無法正確響應通信,導致掃描器無法檢測到該設備。
6. Pull-up Resistors 不適合: 在 I2C 通信中,SDA 和 SCL 線通常需要拉高電阻來確保信號線能夠正確地從低電平回到高電平。當頻率增加時,如果拉高電阻的值過大,線路可能無法在時鐘周期內正確拉高,導致信號出現問題,進而影響通信穩定性。
結論
I2C 掃描器在過高頻率下可能會掃描不到設備,這主要是由於設備支持的頻率上限、信號完整性以及拉高電阻的設置等問題導致的。通過降低 I2C 時鐘頻率並檢查硬件設置,可以提高掃描成功率,確保所有連接的 I2C 設備都能被檢測到。