ESP32学习-I2C(IIC)通信详解与实践
I2C(又称 IIC)是嵌入式开发中最常见的通信协议之一,广泛应用于传感器、显示屏、存储芯片等设备。ESP32 提供了灵活的 I2C 硬件接口,今天我们就来深入学习 I2C 的基本概念、使用流程及 ESP32 实践。
一、基本概念
✅ 什么是 I2C?
I2C(Inter-Integrated Circuit) 是一种由 Philips(飞利浦)发明的串行通信协议,用于主控与多个从设备之间的数据通信。它具有以下特点:
特性 | 说明 |
---|---|
通信方式 | 串行通信(同步) |
连接方式 | 只需两根信号线:SCL(时钟)和 SDA(数据) |
主从结构 | 一个主控(如 ESP32)控制多个从设备 |
唯一地址 | 每个从设备有唯一的 7 位或 10 位地址 |
半双工通信 | 数据是双向的,但一次只能一个方向传输 |
❓ I2C 与 SPI 的区别
对比项 | I2C | SPI |
---|---|---|
信号线 | 2 根(SDA, SCL) | 4 根(MOSI, MISO, SCLK, CS) |
速率 | 一般 100kHz~400kHz | 更高,几 MHz 甚至几十 MHz |
结构 | 多主多从 | 通常为一主多从(点对点) |
成本 | 引脚少,布线简单 | 引脚多,布线复杂 |
应用场景 | 简单控制/低速设备,如传感器 | 高速传输,如屏幕、Flash |
二、使用流程(ESP32 I2C 主机模式)
ESP32 的 I2C 驱动使用 主设备模式(Master) 最多可挂载两个 I2C 接口(I2C_NUM_0 和 I2C_NUM_1),流程如下:
配置 I2C 接口参数(GPIO、速率等)
安装 I2C 驱动
使用
i2c_master_write
/read
等函数读写设备完成通信后可卸载驱动(可选)
三、I2C 端口配置
ESP32 的 I2C 引脚是可选的(不是固定的),你可以选择任意空闲 GPIO 作为 SDA 和 SCL,只要设备支持。
例如我们选:
SDA:GPIO21
SCL:GPIO22
#include "driver/i2c.h"#define I2C_MASTER_NUM I2C_NUM_0 // 使用 I2C0
#define I2C_MASTER_SDA_IO 21
#define I2C_MASTER_SCL_IO 22
#define I2C_MASTER_FREQ_HZ 400000 // 400kHz
#define I2C_MASTER_TX_BUF_DISABLE 0
#define I2C_MASTER_RX_BUF_DISABLE 0void i2c_master_init()
{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};i2c_param_config(I2C_MASTER_NUM, &conf); // 选定iic控制器为I2C0,再配置对应端口信息i2c_driver_install(I2C_MASTER_NUM, conf.mode,I2C_MASTER_RX_BUF_DISABLE,I2C_MASTER_TX_BUF_DISABLE, 0);
}
🔍 SDA/SCL 需要接 上拉电阻(如 4.7kΩ),部分板子已内置。
🔧 I2C_MASTER_RX_BUF_DISABLE
和 TX_BUF_DISABLE
是什么?
这两个宏值为 0
,表示:
你不需要缓冲区(你是主机,数据是你主动读写的,不需要控制器中先存一堆数据)
如果你要使用从机模式(
I2C_MODE_SLAVE
),那就必须配置非零缓冲区长度
💡 一句话总结
i2c_driver_install()
的作用是真正启用 I2C 控制器,它必须在i2c_param_config()
之后调用,且主机模式下接收/发送缓冲区长度必须设为 0。
四、源代码示例(读写一个设备寄存器)
假设我们有一个从设备地址为 0x68
,我们要向其写入一个寄存器,然后再读回来:
#define DEVICE_ADDR 0x68
#define REGISTER_ADDR 0x01// 写一个字节到指定寄存器
esp_err_t i2c_write_byte(uint8_t reg_addr, uint8_t data)
{i2c_cmd_handle_t cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (DEVICE_ADDR << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, reg_addr, true);i2c_master_write_byte(cmd, data, 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;
}// 从指定寄存器读取一个字节
esp_err_t i2c_read_byte(uint8_t reg_addr, uint8_t *data)
{i2c_cmd_handle_t cmd = i2c_cmd_link_create();i2c_master_start(cmd);i2c_master_write_byte(cmd, (DEVICE_ADDR << 1) | I2C_MASTER_WRITE, true);i2c_master_write_byte(cmd, reg_addr, true);i2c_master_start(cmd); // 重启i2c_master_write_byte(cmd, (DEVICE_ADDR << 1) | I2C_MASTER_READ, true);i2c_master_read_byte(cmd, data, 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;
}
五、问题
1.为什么既要指定iic控制器,又可以随意选择端口,STM32中的硬件IIC不是直接与端口绑定了吗?
该处是硬件IIC实现,ESP32几乎所有引脚都是通用的,因此需要手动指定。而stm32固定就映射好了,因此可以不用指定。
六、总结
I2C 是 ESP32 最常用的外设通信协议之一,掌握它是开发各种传感器模块的基础。