I2C 总线协议
I2C(Inter-Integrated Circuit,I²C)是菲利浦半导体(现 NXP)于 1982 年发明的串行总线协议,只需两根线(SDA 数据线、SCL 时钟线)即可连接多达 127 个设备,是传感器模块最常用的通信接口。
I2C 总线核心概念
ESP-IDF I2C Master 初始化(v5.x 新 API)
#include "driver/i2c_master.h"
#include "esp_log.h"
#define I2C_PORT I2C_NUM_0
#define I2C_SDA GPIO_NUM_21
#define I2C_SCL GPIO_NUM_22
#define I2C_SPEED 400000 // 400kHz
static i2c_master_bus_handle_t i2c_bus;
static i2c_master_dev_handle_t bmp280_dev;
void i2c_init(void)
{
i2c_master_bus_config_t bus_cfg = {
.clk_source = I2C_CLK_SRC_DEFAULT,
.i2c_port = I2C_PORT,
.sda_io_num = I2C_SDA,
.scl_io_num = I2C_SCL,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = 1, // 启用内部上拉
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bus_cfg, &i2c_bus));
i2c_device_config_t bmp_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = 0x76, // BMP280 地址(SDO 接 GND)
.scl_speed_hz = I2C_SPEED,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(i2c_bus, &bmp_cfg, &bmp280_dev));
}
void i2c_write_reg(uint8_t reg, uint8_t val)
{
uint8_t buf[2] = {reg, val};
i2c_master_transmit(bmp280_dev, buf, sizeof(buf), -1);
}
void i2c_read_reg(uint8_t reg, uint8_t *buf, size_t len)
{
i2c_master_transmit_receive(bmp280_dev, ®, 1, buf, len, -1);
}
DHT22 温湿度传感器(单总线)
DHT22(又名 AM2302)是一款极为常见的数字温湿度传感器,测量范围:温度 -40~+80°C(精度 ±0.5°C),湿度 0~100% RH(精度 ±2%)。它使用专有的单总线(1-Wire-like)协议通信,只需一根 GPIO 线。
/* 简化版 DHT22 读取(实际项目推荐使用 esp-idf-lib 的 dht 组件)*/
#include "driver/gpio.h"
#include "esp_timer.h"
#define DHT22_PIN GPIO_NUM_4
static int64_t wait_level(int level, int64_t timeout_us)
{
int64_t start = esp_timer_get_time();
while (gpio_get_level(DHT22_PIN) != level) {
if (esp_timer_get_time() - start > timeout_us) return -1;
}
return esp_timer_get_time() - start;
}
esp_err_t dht22_read(float *temperature, float *humidity)
{
uint8_t data[5] = {0};
/* 发送起始信号:拉低 18ms */
gpio_set_direction(DHT22_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(DHT22_PIN, 0);
esp_rom_delay_us(18000);
gpio_set_level(DHT22_PIN, 1);
esp_rom_delay_us(40);
gpio_set_direction(DHT22_PIN, GPIO_MODE_INPUT);
/* 等待 DHT22 响应 */
if (wait_level(0, 100) < 0) return ESP_ERR_TIMEOUT;
if (wait_level(1, 100) < 0) return ESP_ERR_TIMEOUT;
if (wait_level(0, 100) < 0) return ESP_ERR_TIMEOUT;
/* 读取 40bit 数据 */
for (int i = 0; i < 40; i++) {
if (wait_level(1, 65) < 0) return ESP_ERR_INVALID_RESPONSE;
int64_t high_us = wait_level(0, 90);
if (high_us < 0) return ESP_ERR_INVALID_RESPONSE;
data[i / 8] <<= 1;
if (high_us > 45) data[i / 8] |= 1; // >45μs = bit 1
}
/* 校验 */
if (data[4] != ((data[0] + data[1] + data[2] + data[3]) & 0xFF))
return ESP_ERR_INVALID_CRC;
*humidity = ((uint16_t)data[0] << 8 | data[1]) / 10.0f;
*temperature = ((uint16_t)(data[2] & 0x7F) << 8 | data[3]) / 10.0f;
if (data[2] & 0x80) *temperature = -*temperature; // 负温度
return ESP_OK;
}
DHT22 采样间隔至少 2 秒。连续读取会导致传感器内部状态错误,返回错误数据。如果需要更高频率的温度测量,请考虑使用 I2C 接口的 BMP280 或 SHT31。
BMP280 气压/温度传感器(I2C)
BMP280 是博世(Bosch)出品的高精度气压温度传感器,气压精度 ±1hPa,温度精度 ±1°C,通过 I2C 或 SPI 接口通信。常用于海拔计算(气压每升高 100m 约下降 12hPa)。
/* 使用 ESP-IDF 组件管理器安装 bmp280 驱动:*/
// idf.py add-dependency "idf-extra-components/bmp280"
#include "bmp280.h"
void bmp280_task(void *arg)
{
bmp280_params_t params;
bmp280_init_default_params(¶ms);
bmp280_t bmp280_dev = {
.i2c_dev = {
.port = I2C_NUM_0,
.addr = BMP280_I2C_ADDRESS_0, // 0x76
.cfg = { .sda_io_num = 21, .scl_io_num = 22,
.master.clk_speed = 400000 }
}
};
bmp280_init(&bmp280_dev, ¶ms);
float pressure, temperature, humidity;
while (1) {
bmp280_read_float(&bmp280_dev, &temperature, &pressure, &humidity);
ESP_LOGI("BMP280", "温度: %.2f°C 气压: %.2f hPa",
temperature, pressure / 100.0f);
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
OLED 显示(SSD1306 + I2C)
SSD1306 是 128×64 点阵 OLED 显示控制器,通过 I2C(地址 0x3C/0x3D)或 SPI 驱动。ESP-IDF 生态中常用的驱动库是 esp_lvgl_port(配合 LVGL GUI 框架)或轻量级的 ssd1306 组件。
// idf.py add-dependency "nopnop2002/ssd1306"
#include "ssd1306.h"
void oled_demo(void)
{
SSD1306_t oled;
i2c_master_init(&oled, 21, 22, -1); // SDA=21, SCL=22, RST=-1(无)
ssd1306_init(&oled, 128, 64);
ssd1306_clear_screen(&oled, false);
ssd1306_contrast(&oled, 0xFF);
ssd1306_display_text(&oled, 0, "ESP32 IoT", 9, false);
ssd1306_display_text(&oled, 2, "Temp: 25.6C", 11, false);
ssd1306_display_text(&oled, 4, "Humi: 65.3%", 11, false);
}
MPU6050 六轴 IMU
MPU6050 集成三轴加速度计和三轴陀螺仪,I2C 地址 0x68(AD0 接 GND)或 0x69(AD0 接 VCC)。常用于姿态检测、计步器、抖动补偿等场景。
#define MPU6050_ADDR 0x68
#define MPU_PWR_MGT1 0x6B
#define MPU_ACCEL_XOUT 0x3B
#define MPU_GYRO_XOUT 0x43
void mpu6050_init(void)
{
i2c_write_reg(MPU_PWR_MGT1, 0x00); // 唤醒,退出休眠模式
}
void mpu6050_read(void)
{
uint8_t raw[14];
i2c_read_reg(MPU_ACCEL_XOUT, raw, 14); // 一次读取加速度+温度+陀螺仪
int16_t ax = (raw[0] << 8) | raw[1];
int16_t ay = (raw[2] << 8) | raw[3];
int16_t az = (raw[4] << 8) | raw[5];
int16_t gx = (raw[8] << 8) | raw[9];
int16_t gy = (raw[10] << 8) | raw[11];
int16_t gz = (raw[12] << 8) | raw[13];
/* 量程 ±2g 时:1g = 16384 LSB */
ESP_LOGI("MPU", "Accel: X=%.2fg Y=%.2fg Z=%.2fg",
ax/16384.0f, ay/16384.0f, az/16384.0f);
/* 量程 ±250°/s 时:1°/s = 131 LSB */
ESP_LOGI("MPU", "Gyro: X=%.1f Y=%.1f Z=%.1f deg/s",
gx/131.0f, gy/131.0f, gz/131.0f);
}
esp-idf-lib 是 ESP-IDF 生态中最完整的传感器驱动库集合,包含 DHT、BMP280、MPU6050、SSD1306、DS18B20、ADS1115 等数十种传感器的经过测试的驱动,大多数情况下无需自己从零实现。