返回首页I2C 传感器学习笔记
概述
I2C (Inter-Integrated Circuit) 是常用的低速串行通信协议,广泛用于连接传感器、EEPROM、RTC 等外设。本示例展示如何使用 Zephyr Sensor API 读取 I2C 传感器数据。
1. I2C 基础概念
1.1 I2C 协议特点
| 特性 | 说明 |
| 引脚 | SDA (数据)、SCL (时钟) |
| 速率 | 标准 100kHz、快速 400kHz、高速 3.4MHz |
| 地址 | 7位或10位地址 |
| 主从 | 一主多从,主设备发起通信 |
| 电气 | 开漏输出,需要上拉电阻 |
1.2 I2C 时序
SDA: ───┐ ┌───────┐ ┌───
└─────┘ └─────┘
SCL: ───┐ ┌───────┐ ┌───
└─────┘ └─────┘
起始条件:SDA 从高到低,SCL 为高
数据位:SDA 在 SCL 低时改变
停止条件:SDA 从低到高,SCL 为高
2. 设备树配置
2.1 I2C 总线配置
&i2c0 {
status = "okay";
clock-frequency = <I2C_BITRATE_STANDARD>; // 100kHz
bme280@76 {
compatible = "bosch,bme280";
reg = <0x76>; // I2C 设备地址
status = "okay";
};
};
2.2 传感器别名配置
/ {
aliases {
accel0 = &lis2dh12;
};
lis2dh12: lis2dh12@18 {
compatible = "st,lis2dh";
reg = <0x18>;
status = "okay";
};
};
3. Sensor API 核心操作
3.1 获取传感器设备
// 从设备树获取
const struct device *dev = DEVICE_DT_GET_ANY(bosch_bme280);
// 从别名获取
const struct device *const sensors[] = {
DEVICE_DT_GET(DT_ALIAS(accel0)),
};
// 检查设备就绪
if (!device_is_ready(dev)) {
printk("Device not ready\n");
}
3.2 同步读取(传统方式)
struct sensor_value temp, press, humidity;
// 1. 采集数据
int ret = sensor_sample_fetch(dev);
if (ret < 0) {
printk("Fetch failed: %d\n", ret);
}
// 2. 获取具体通道数据
ret = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
ret = sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);
ret = sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity);
3.3 传感器通道类型
// 加速度
SENSOR_CHAN_ACCEL_X
SENSOR_CHAN_ACCEL_Y
SENSOR_CHAN_ACCEL_Z
SENSOR_CHAN_ACCEL_XYZ
// 陀螺仪
SENSOR_CHAN_GYRO_X
SENSOR_CHAN_GYRO_Y
SENSOR_CHAN_GYRO_Z
// 环境传感器
SENSOR_CHAN_AMBIENT_TEMP
SENSOR_CHAN_HUMIDITY
SENSOR_CHAN_PRESS
SENSOR_CHAN_GAS_RES
// 磁力计
SENSOR_CHAN_MAGN_X
SENSOR_CHAN_MAGN_Y
SENSOR_CHAN_MAGN_Z
// 光照/颜色
SENSOR_CHAN_LIGHT
SENSOR_CHAN_RED
SENSOR_CHAN_GREEN
SENSOR_CHAN_BLUE
3.4 传感器值转换
// sensor_value 结构
struct sensor_value {
int32_t val1; // 整数部分
int32_t val2; // 小数部分 (百万分之一)
};
// 转换为 double
double val = sensor_value_to_double(&temp);
// 例如:val1 = 25, val2 = 500000 → 25.5
// 转换为整数(毫单位)
int32_t millivolts = sensor_value_to_milli(&voltage);
4. 传感器属性设置
4.1 设置采样频率
struct sensor_value odr;
odr.val1 = 100; // 100 Hz
odr.val2 = 0;
int ret = sensor_attr_set(
dev, // 设备
SENSOR_CHAN_ACCEL_XYZ, // 通道
SENSOR_ATTR_SAMPLING_FREQUENCY, // 属性
&odr // 值
);
4.2 获取采样频率
struct sensor_value odr;
sensor_attr_get(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr);
printk("ODR: %d Hz\n", odr.val1);
4.3 常用属性
// 采样频率
SENSOR_ATTR_SAMPLING_FREQUENCY
// 满量程范围
SENSOR_ATTR_FULL_SCALE
// 数据就绪触发
SENSOR_ATTR_CONFIGURATION
// 偏移量校准
SENSOR_ATTR_OFFSET
// 校准斜率
SENSOR_ATTR_SLOPE
// 阈值
SENSOR_ATTR_ALERT_THRESHOLD
5. 异步 Sensor API(新方式)
5.1 定义 IO 设备
SENSOR_DT_READ_IODEV(
iodev, // IO 设备名
DT_ALIAS(temp0), // 设备节点示例
{SENSOR_CHAN_AMBIENT_TEMP, 0}, // 通道 0
{SENSOR_CHAN_HUMIDITY, 0}, // 通道 1
{SENSOR_CHAN_PRESS, 0} // 通道 2
);
RTIO_DEFINE(ctx, 1, 1); // RTIO 上下文
5.2 异步读取
uint8_t buf[128];
int rc = sensor_read(&iodev, &ctx, buf, 128);
// 获取解码器
const struct sensor_decoder_api *decoder;
sensor_get_decoder(dev, &decoder);
// 解码数据
struct sensor_q31_data temp_data;
decoder->decode(buf,
(struct sensor_chan_spec) {SENSOR_CHAN_AMBIENT_TEMP, 0},
&temp_fit, 1, &temp_data);
printk("Temp: %d.%d\n",
temp_data.readings[0].temperature >> temp_data.shift,
temp_data.readings[0].temperature & ((1 << temp_data.shift) - 1));
6. I2C 底层 API(直接使用)
6.1 写操作
// I2C 写一个字节
uint8_t reg = 0xF4; // 寄存器地址
uint8_t data = 0x27; // 数据
int ret = i2c_write(
dev, // I2C 设备
&data, // 数据
1, // 长度
0x76 // 从机地址
);
6.2 读操作
// I2C 读操作(先写寄存器地址,再读数据)
uint8_t reg = 0xF7; // 要读的寄存器
uint8_t buf[6]; // 读缓冲区
int ret = i2c_write_read(
dev,
0x76, // 从机地址
®, 1, // 写:寄存器地址
buf, 6 // 读:6 字节数据
);
6.3 扫描总线
// 扫描 I2C 总线,查找设备
for (uint8_t addr = 0x08; addr < 0x77; addr++) {
uint8_t dummy;
if (i2c_read(i2c_dev, &dummy, 0, addr) == 0) {
printk("Found device at 0x%02X\n", addr);
}
}
7. nRF54L15 I2C 配置
7.1 设备树配置
&i2c20 {
status = "okay";
pinctrl-0 = <&i2c20_default>;
pinctrl-1 = <&i2c20_sleep>;
pinctrl-names = "default", "sleep";
my_sensor@48 {
compatible = "my,vendor,sensor";
reg = <0x48>;
status = "okay";
};
};
7.2 引脚配置
&pinctrl {
i2c20_default: i2c20_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 1, 10)>, // P1.10
<NRF_PSEL(TWIM_SCL, 1, 11)>; // P1.11
};
};
};
8. 实际应用示例
8.1 BME280 传感器读取
const struct device *dev = DEVICE_DT_GET_ANY(bosch_bme280);
while (1) {
sensor_sample_fetch(dev);
struct sensor_value temp, press, hum;
sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);
sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &hum);
printk("T: %.2f°C, P: %.2fhPa, H: %.2f%%\n",
sensor_value_to_double(&temp),
sensor_value_to_double(&press) / 100, // hPa
sensor_value_to_double(&hum));
k_sleep(K_MSEC(1000));
}
8.2 加速度计数据读取
static const enum sensor_channel channels[] = {
SENSOR_CHAN_ACCEL_X,
SENSOR_CHAN_ACCEL_Y,
SENSOR_CHAN_ACCEL_Z,
};
int print_accel(const struct device *dev)
{
struct sensor_value accel[3];
sensor_sample_fetch(dev);
for (int i = 0; i < 3; i++) {
sensor_channel_get(dev, channels[i], &accel[i]);
}
printk("Accel: X=%.3f Y=%.3f Z=%.3f m/s^2\n",
sensor_value_to_double(&accel[0]),
sensor_value_to_double(&accel[1]),
sensor_value_to_double(&accel[2]));
}
9. 配置选项 (prj.conf)
CONFIG_I2C=y # 启用 I2C 驱动
CONFIG_SENSOR=y # 启用 Sensor 子系统
CONFIG_SENSOR_ASYNC_API=y # 启用异步 API(可选)
# 具体传感器驱动
CONFIG_BME280=y # BME280 驱动
CONFIG_LIS2DH=y # LIS2DH 加速度计驱动
CONFIG_CBPRINTF_FP_SUPPORT=y # 浮点打印支持
10. 关键问题总结
| 问题 | 答案 |
| I2C 地址在哪设? | 设备树 reg 属性 |
| 如何读取传感器? | sensor_sample_fetch() + sensor_channel_get() |
| 采样频率怎么改? | sensor_attr_set(SENSOR_ATTR_SAMPLING_FREQUENCY) |
| I2C 速率怎么设? | 设备树 clock-frequency |
| 数据格式是什么? | struct sensor_value (整数+小数) |
11. 与其他示例对比
| 示例 | 通信方式 | API 层级 |
| I2C 传感器 | I2C | Sensor API(高层) |
| SPI spi_flash | SPI | Flash API(中层) |
| UART echo_bot | UART | 驱动 API(低层) |
12. 学习心得
- Sensor API:提供统一接口,隐藏硬件差异
- 设备树配置:I2C 地址、引脚都在 DTS 中配置
- 同步 vs 异步:新 API 支持异步读取,适合高吞吐场景
- I2C 调试:先用
i2c_write_read() 底层 API 确认通信正常
总结:三大外设学习笔记全部完成!
| 示例 | 学习笔记文件 |
| PWM LED | notes/PWM_LED_Learning_Notes.md |
| ADC 采样 | notes/ADC_Learning_Notes.md |
| I2C 传感器 | notes/I2C_Sensor_Learning_Notes.md |
小白 🤖 2026-03-14