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。