ESP32- 开发笔记- 软件开发 5 -I2C

1 I2C 背景介绍

ESP32 的 I²C(Inter-Integrated Circuit)总线是一个非常常用的串行通信接口,广泛用于与各种外围设备(如传感器、显示屏、EEPROM 等)进行通信。

1.1 I²C 基本原理

I²C 是一种 双线通信协议,使用两根线进行主从式通信:

  1. SDA(Serial Data):数据线

  2. SCL(Serial Clock):时钟线

  3. 特点包括:

支持多个主机和多个从设备

每个设备通过地址区分(7 位或 10 位地址)

半双工通信(主机控制通信过程)

1.2 ESP32 上的 I²C 特点

1.2.1 控制器

支持多达两个硬件 I²C 控制器:I2C_NUM_0 和 I2C_NUM_1。 可以使用任意 GPIO 引脚作为 SDA 和 SCL(自由配置)。

| I²C 通道 | SDA 默认引脚 | SCL 默认引脚 |
| ------   | --------    | --------    |
| I2C0     | GPIO21      | GPIO22      |

1.2.2 速率

ESP32 支持以下 I²C 速度:

标准模式:100 kHz

快速模式:400 kHz

高速模式:ESP32 不原生支持 3.4 MHz(需扩展)

1.3 应用范围

  1. OLED 显示屏(如 SSD1306)
  2. 温湿度传感器(如 SHT30、BME280)
  3. EEPROM(如 AT24C32)
  4. IO 扩展芯片(如 PCF8574)

2 配置流程

包含常用的头文件

#include "driver/i2c.h"

2.1 初始化配置结构体

2.1.1 配置函数

esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf);

作用:配置 I²C 控制器的参数,比如 SDA/SCL 引脚、通信速率、主从模式等。

参数:

i2c_num: 控制器编号(如 I2C_NUM_0)

i2c_conf: 配置结构体 i2c_config_t

返回值:成功返回 ESP_OK

2.1.2 例子

i2c_config_t conf = {
    .mode = I2C_MODE_MASTER,
    .sda_io_num = GPIO_NUM_21,
    .scl_io_num = GPIO_NUM_22,
    .sda_pullup_en = GPIO_PULLUP_ENABLE,
    .scl_pullup_en = GPIO_PULLUP_ENABLE,
    .master.clk_speed = 100000, // 100kHz
};
i2c_param_config(I2C_NUM_0, &conf);
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));

2.2 安装驱动

2.2.1 i2c_driver_install

esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode,
                             size_t slv_rx_buf_len, size_t slv_tx_buf_len, int intr_alloc_flags);

作用:安装 I²C 驱动程序,使配置生效。

参数:

i2c_num: I²C 控制器编号

mode: 通信模式(I2C_MODE_MASTER 或 I2C_MODE_SLAVE)

slv_rx_buf_len / slv_tx_buf_len: 从机接收/发送缓冲区大小(主机模式下设为 0)

intr_alloc_flags: 中断分配标志(通常设为 0)

返回值:成功返回 ESP_OK

2.2.2 案例说明

i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);

2.3 通信操作

2.3.1 i2c_cmd_link_create

 i2c_cmd_handle_t i2c_cmd_link_create();

作用:创建一个 I²C 命令链接句柄,用于构建一次传输过程。
返回值:返回句柄,用于后续写入、读、发送起始信号等操作。

2.3.2 i2c_master_start()

esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle);

作用:添加 I²C 起始条件(Start condition),开启通信。
参数:命令句柄 cmd_handle
必须是第一个操作

2.3.3 i2c_master_write_byte()

esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en);

作用:写入一个字节(通常是地址 + 读写位,或数据)
参数:
data: 要写的字节
ack_en: 是否期望 ACK 应答(设为 true)

2.3.4 i2c_master_write()

esp_err_t i2c_master_write(i2c_cmd_handle_t cmd_handle, const uint8_t *data,
                           size_t data_len, bool ack_en);

作用:连续写多个字节数据

参数:

data: 数据指针

data_len: 长度

ack_en: 每个字节是否检查 ACK

2.3.5 i2c_master_read()

esp_err_t i2c_master_read(i2c_cmd_handle_t cmd_handle, uint8_t *data,
                          size_t data_len, i2c_ack_type_t ack);

作用:读取多个字节的数据

参数:

data: 接收缓冲区

ack: 最后一个字节是否发送 ACK(通常最后一个字节发送 NACK)

2.3.6 i2c_master_stop()

esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle);

作用:添加停止条件(Stop condition),终止通信

2.3.7 i2c_master_cmd_begin()

esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle,
                               TickType_t ticks_to_wait);

作用:执行上述构建好的命令链

参数:

ticks_to_wait: 超时时间(如 pdMS_TO_TICKS(1000) 表示等待 1000 ms)

2.3.8 i2c_cmd_link_delete()

esp_err_t i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle);

作用:释放命令链占用的内存资源

2.4 写数据

esp_err_t i2c_master_write_slave(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, size_t len) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_write(cmd, data, len, true);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

2.5 读数据

esp_err_t i2c_master_read_slave(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, size_t len) {
    i2c_cmd_handle_t cmd = i2c_cmd_link_create();
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_WRITE, true);
    i2c_master_write_byte(cmd, reg_addr, true);
    i2c_master_start(cmd);
    i2c_master_write_byte(cmd, (dev_addr << 1) | I2C_MASTER_READ, true);
    if (len > 1) {
        i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
    }
    i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
    i2c_master_stop(cmd);
    esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_PERIOD_MS);
    i2c_cmd_link_delete(cmd);
    return ret;
}

3 其他

3.1 SP_ERROR_CHECK 宏详解

ESP_ERROR_CHECK 是 ESP-IDF 中一个非常有用的错误处理宏,它用于检查 ESP-IDF 函数的返回值并自动处理错误。

基本功能

ESP_ERROR_CHECK 宏会检查传入的表达式(通常是函数调用)的返回值.

如果返回值不是 ESP_OK(即发生了错误),打印错误信息(包括错误代码和错误位置),调用 abort() 终止程序执行

// 普通方式
esp_err_t err = i2c_param_config(I2C_NUM_0, &conf);
if (err != ESP_OK) {
    ESP_LOGE(TAG, "i2c_param_config failed: %s", esp_err_to_name(err));
    return;
}

// 使用 ESP_ERROR_CHECK 简化
ESP_ERROR_CHECK(i2c_param_config(I2C_NUM_0, &conf));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数贾电子科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值