可以的。ESP32-S3 的 I²C 总线本身就是多主从、多设备共享的,只要两块设备的从机地址不同,并且都工作在同样的电平和速率下,就可以同时挂在一条 SDA/SCL 上。下面给出一个简单示例,展示如何在同一个 I2C 端口(例如 I2C_NUM_0)上,先扫描确认 LCD 和 IP5356M 的从机地址,然后初始化并分别与它们通信。

#include "driver/i2c.h"
#include "esp_log.h"
#include "esp_err.h"
static const char *TAG = "i2c_multi";
// I2C 引脚和参数
#define I2C_MASTER_SCL_IO 22 // SCL 引脚
#define I2C_MASTER_SDA_IO 21 // SDA 引脚
#define I2C_MASTER_NUM I2C_NUM_0
#define I2C_MASTER_FREQ_HZ 100000
#define I2C_MASTER_TX_BUF_DISABLE 0
#define I2C_MASTER_RX_BUF_DISABLE 0
#define I2C_MASTER_TIMEOUT_MS 1000
// 假设 LCD 的 I2C 地址是 0x3C,IP5356M 的地址是 0x75
#define LCD_I2C_ADDR 0x3C
#define IP5356M_ADDR 0x75
// 初始化 I2C 总线
static esp_err_t i2c_master_init(void)
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.scl_io_num = I2C_MASTER_SCL_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ,
};
ESP_RETURN_ON_ERROR(i2c_param_config(I2C_MASTER_NUM, &conf), TAG, "param_config");
ESP_RETURN_ON_ERROR(i2c_driver_install(I2C_MASTER_NUM, conf.mode,
I2C_MASTER_RX_BUF_DISABLE,
I2C_MASTER_TX_BUF_DISABLE, 0),
TAG, "driver_install");
return ESP_OK;
}
// 扫描 I2C 总线上所有设备
static void i2c_scan_bus(void)
{
ESP_LOGI(TAG, "--- I2C 总线扫描开始 ---");
for (uint8_t addr = 1; addr < 0x78; addr++) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd,
pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
i2c_cmd_link_delete(cmd);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "找到设备,地址=0x%02X", addr);
}
}
ESP_LOGI(TAG, "--- 扫描结束 ---");
}
// 向 IP5356M 读取一个寄存器示例
static esp_err_t ip5356m_read_reg(uint8_t reg, uint8_t *out_data)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
// 写寄存器地址
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (IP5356M_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(cmd, reg, true);
// 读数据
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (IP5356M_ADDR << 1) | I2C_MASTER_READ, true);
i2c_master_read_byte(cmd, out_data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd,
pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
i2c_cmd_link_delete(cmd);
return ret;
}
// 向 LCD 发送命令/数据示例(以 SSD1306 为例)
static esp_err_t lcd_send_cmd(uint8_t cmd)
{
i2c_cmd_handle_t handle = i2c_cmd_link_create();
// 控制字节 0x00 表示写命令
i2c_master_start(handle);
i2c_master_write_byte(handle, (LCD_I2C_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_write_byte(handle, 0x00, true);
i2c_master_write_byte(handle, cmd, true);
i2c_master_stop(handle);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, handle,
pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
i2c_cmd_link_delete(handle);
return ret;
}
void app_main(void)
{
ESP_ERROR_CHECK(i2c_master_init());
i2c_scan_bus();
// 读取 IP5356M 的某个状态寄存器
uint8_t batt_volt;
if (ip5356m_read_reg(0x78, &batt_volt) == ESP_OK) {
ESP_LOGI(TAG, "IP5356M 电池电压寄存器(0x78)=0x%02X", batt_volt);
} else {
ESP_LOGW(TAG, "读取 IP5356M 失败");
}
// 给 LCD 发送一个“显示开”命令示例
if (lcd_send_cmd(0xAF) == ESP_OK) {
ESP_LOGI(TAG, "LCD 命令 0xAF(显示开) 已发送");
} else {
ESP_LOGW(TAG, "向 LCD 发送命令失败");
}
// 后续可继续操作 IP5356M 和 LCD……
}
要点总结:
-
唯一地址:确认 LCD(如 SSD1306 通常是 0x3C 或 0x3D)和 IP5356M(常见 0x75)地址不冲突;否则需更改其中一个设备的地址或使用多个 I2C 总线。
-
拉拔电阻:I²C 总线需要外部 4.7kΩ 上拉到 3.3V,ESP32-S3 板上常自带,也要保证两端有。
-
电平兼容:两块外设都工作在 3.3V,若有 5V 设备需电平转换。
-
总线速率:示例使用 100kHz,若有高速需求可设 400kHz,但要确认器件支持。
-
驱动复用:一条总线只需调用一次
i2c_driver_install,后面通过不同地址读写即可。
只要满足这些要求,就可以放心地在 ESP32-S3 的同一 I²C 总线上同时挂载 LCD 显示屏和 IP5356M。
1246

被折叠的 条评论
为什么被折叠?



