2. 读取Sensor ID
任务目标
本案例实现通过I2C总线读取Camera Sensor的ID寄存器(通常为8位或16位地址),将读取到的ID值与预期值比对,验证主机与Sensor之间的I2C通信是否正确,并在串口终端打印ID值。
环境与依赖
- 硬件:Linux主机(或开发板)与Sensor模组通过I2C连接,Sensor供电正常,复位引脚已释放
- 软件:Linux内核I2C设备驱动(i2c-dev)、i2c-tools工具包(含
i2cget/i2cset)、C编译器(gcc) - Sensor数据手册中需确认:I2C从机地址、ID寄存器地址、ID寄存器位宽(8位/16位)、预期ID值
实现方案
采用Linux用户态I2C读写方式,通过/dev/i2c-N设备节点直接访问Sensor。核心逻辑为:打开I2C总线设备 → 设置从机地址 → 写入寄存器地址 → 读取ID值 → 与预期值比较并打印。该方式无需编写内核驱动,适合驱动开发前期验证通信链路。
关键完整代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
// ===== 配置区(根据实际Sensor修改) =====
#define I2C_BUS_PATH "/dev/i2c-1" // I2C总线设备节点
#define SENSOR_I2C_ADDR 0x36 // Sensor 7位从机地址
#define ID_REG_ADDR 0x0000 // ID寄存器地址(16位地址示例)
#define ID_REG_WIDTH 8 // ID寄存器位宽:8或16
#define EXPECTED_ID 0x0A // 预期ID值(来自数据手册)
// =========================================
static int read_sensor_id(int fd, uint16_t reg_addr, int width, uint16_t *id) {
// 写入寄存器地址(16位地址需分两次发送)
uint8_t reg_buf[2] = { (reg_addr >> 8) & 0xFF, reg_addr & 0xFF };
if (write(fd, reg_buf, sizeof(reg_buf)) != sizeof(reg_buf)) {
perror("write reg addr");
return -1;
}
// 读取ID值
uint8_t data[2] = {0};
if (width == 8) {
if (read(fd, data, 1) != 1) {
perror("read 8bit id");
return -1;
}
*id = data[0];
} else { // 16位
if (read(fd, data, 2) != 2) {
perror("read 16bit id");
return -1;
}
*id = (data[0] << 8) | data[1];
}
return 0;
}
int main(void) {
int fd = open(I2C_BUS_PATH, O_RDWR);
if (fd < 0) {
perror("open i2c bus");
return 1;
}
// 设置从机地址
if (ioctl(fd, I2C_SLAVE, SENSOR_I2C_ADDR) < 0) {
perror("ioctl set slave addr");
close(fd);
return 1;
}
uint16_t sensor_id = 0;
if (read_sensor_id(fd, ID_REG_ADDR, ID_REG_WIDTH, &sensor_id) != 0) {
close(fd);
return 1;
}
printf("Sensor ID = 0x%02X\n", sensor_id);
if (sensor_id == EXPECTED_ID) {
printf("I2C communication OK: ID matches expected value.\n");
} else {
printf("WARNING: ID mismatch! Expected 0x%02X, got 0x%02X\n",
EXPECTED_ID, sensor_id);
}
close(fd);
return 0;
}
编译与运行
# 编译
gcc -o read_sensor_id read_sensor_id.c
# 运行(需root权限或具有/dev/i2c-1访问权限)
sudo ./read_sensor_id
验证方法与判定标准
- 通信正常判定:程序输出
Sensor ID = 0x0A且包含I2C communication OK,说明I2C读写链路正确,Sensor响应正常。 - ID不匹配:若输出ID与预期不符,检查从机地址、寄存器地址、位宽配置是否正确,以及Sensor是否处于正常上电状态。
- 无响应/超时:若程序在
read处阻塞或返回错误,使用i2cdetect -y 1确认Sensor是否在总线上被发现(地址是否正确)。 - 辅助排查:可用
i2cget -y 1 0x36 0x00直接读取寄存器值,与程序输出交叉验证。
常见问题
- 地址错误:确认使用的是7位地址而非8位地址(8位地址需左移1位)。
- 寄存器地址宽度:部分Sensor使用8位寄存器地址,此时只需发送1字节地址;本代码按16位地址实现,若为8位地址需修改
reg_buf为单字节。 - I2C总线编号:通过
ls /dev/i2c-*确认实际总线节点,可能不是i2c-1。