4. 陀螺仪数据采集:初始化配置、读取原始数据、数据校验、采样率设置、FIFO使用

各位同学好,我是老赵。今天咱们聊聊陀螺仪数据采集这件事。说实话,我在做OIS防抖的头两年,踩过最多的坑就是数据采集阶段。你想想看,算法再牛,如果源头数据是脏的,后面全是白搭。

这一节,我带你手把手把陀螺仪的数据通路打通。从寄存器配置到FIFO管理,咱们一条龙讲清楚。

4.1 初始化配置——别小看这一步

陀螺仪上电后,不是拿来就能用的。你得先跟它打个招呼,告诉它:「嘿,我要开始干活了」。这个打招呼的过程,就是初始化配置。

我个人习惯把初始化分成三步:

  1. 复位传感器——让内部状态回到已知的初始值
  2. 配置电源模式——选择正常模式还是低功耗模式
  3. 设置量程和带宽——决定你能测多大的角速度

以ICM-20602这颗常用芯片为例,我贴一段实际项目里用过的初始化代码:

// 初始化ICM-20602陀螺仪
void gyro_init(void) {
    uint8_t who_am_i;
    
    // 第一步:复位
    spi_write_reg(REG_PWR_MGMT_1, 0x80);  // 复位所有寄存器
    delay_ms(100);  // 等它缓过来
    
    // 第二步:唤醒并选择时钟源
    spi_write_reg(REG_PWR_MGMT_1, 0x01);  // 用PLL时钟,退出休眠
    
    // 第三步:配置量程为±2000dps
    spi_write_reg(REG_GYRO_CONFIG, 0x18); // 满量程2000dps
    
    // 第四步:配置数字低通滤波器,带宽约41Hz
    spi_write_reg(REG_CONFIG, 0x03);      // DLPF_CFG = 3
    
    // 校验:读WHO_AM_I寄存器
    who_am_i = spi_read_reg(REG_WHO_AM_I);
    if (who_am_i != 0x12) {
        // 我遇到过芯片焊接虚焊,读回来全是0xFF
        // 这时候别慌,先检查硬件连接
        error_handler("Gyro not found!");
    }
}
⚠️ 注意:复位后一定要加延时。我曾经图省事,复位完立刻配寄存器,结果配置写不进去。后来查手册才发现,复位后芯片需要至少50ms才能稳定响应SPI通信。

4.2 读取原始数据——三轴数据怎么拿

初始化完了,就该读数据了。陀螺仪输出的是三个轴的角速度:X轴、Y轴、Z轴。每个轴16位,所以一次完整读取要拿6个字节。

这里有个关键点:数据是16位有符号数,高位在前(Big-Endian)。我见过有人直接拿两个字节拼成int16,结果符号位搞反了,出来的数据忽正忽负,查了半天。

// 读取三轴陀螺仪数据
typedef struct {
    int16_t x;
    int16_t y;
    int16_t z;
} gyro_data_t;

gyro_data_t gyro_read_raw(void) {
    uint8_t buf[6];
    gyro_data_t data;
    
    // 从0x43寄存器开始,连续读6个字节
    spi_read_burst(REG_GYRO_XOUT_H, buf, 6);
    
    // 拼成16位有符号数
    data.x = (int16_t)((buf[0] << 8) | buf[1]);
    data.y = (int16_t)((buf[2] << 8) | buf[3]);
    data.z = (int16_t)((buf[4] << 8) | buf[5]);
    
    return data;
}

读出来的原始值怎么转成物理单位?很简单:

角速度(dps) = 原始值 / 满量程灵敏度

比如量程是±2000dps,灵敏度是16.4 LSB/dps。那么:

实际角速度 = 原始值 / 16.4

量程 灵敏度 (LSB/dps)
±250 dps 131.0
±500 dps 65.5
±1000 dps 32.8
±2000 dps 16.4

4.3 数据校验——别信数据,信校验

数据读回来了,你敢直接用吗?我不敢。SPI通信受干扰、时钟抖动、甚至线太长,都可能让数据出错。

我常用的校验手段有三个:

  • WHO_AM_I校验——每次初始化后读一次,确认芯片活着
  • 数据范围检查——如果读出来的值超过物理极限,直接丢弃
  • 连续采样一致性——相邻两帧数据突变太大,大概率是异常

实战经验:我在做一款手机OIS时,发现偶尔会出现一个跳变很大的数据点。排查了很久,最后发现是SPI时钟频率太高(10MHz),线缆太长导致信号反射。把时钟降到5MHz后,问题消失。

// 数据校验示例
int gyro_data_check(gyro_data_t *data) {
    // 检查范围:±2000dps对应的原始值范围
    if (abs(data->x) > 32760 || abs(data->y) > 32760 || abs(data->z) > 32760) {
        return -1;  // 数据异常
    }
    
    // 检查与上一帧的差值(假设上一帧保存在prev中)
    if (abs(data->x - prev.x) > 5000) {
        return -2;  // 突变过大
    }
    
    return 0;  // 数据正常
}

4.4 采样率设置——快了不行,慢了也不行

采样率怎么选?说白了,取决于你的应用场景。

做OIS防抖,我一般用1kHz的采样率。为什么?因为手持抖动的频率主要在5-20Hz,根据奈奎斯特定理,采样率至少是最高频率的两倍。但实际中,为了留出余量,我们通常取10倍以上。

采样率通过配置内部时钟分频器来设置:

// 设置采样率为1kHz
// 内部时钟 = 32.768kHz
// 分频系数 = 32.768 / 1 = 32.768,取整为33
uint8_t sample_rate_div = 33 - 1;  // 寄存器值 = 分频系数 - 1
spi_write_reg(REG_SMPLRT_DIV, sample_rate_div);

💡 小技巧:采样率不是越高越好。采样率太高,数据量暴增,MCU处理不过来,反而会丢帧。我一般控制在1kHz-2kHz之间,够用又不浪费算力。

4.5 FIFO使用——别让CPU累死

如果每次数据来了都去中断CPU,那CPU啥也别干了。这时候FIFO就派上用场了。

FIFO是个硬件缓冲区,陀螺仪自己把数据往里塞,你啥时候有空了,一次性读出来就行。

FIFO的使用流程:

  1. 使能FIFO,并选择要存入的数据类型(比如只存陀螺仪数据)
  2. 设置FIFO水印(Watermark)——当数据量达到这个值时,触发中断
  3. 在中断服务程序里,一次性读取FIFO中的所有数据
// 配置FIFO
void fifo_config(void) {
    // 使能FIFO
    spi_write_reg(REG_USER_CTRL, 0x40);  // FIFO_EN = 1
    
    // 选择存入FIFO的数据:只存陀螺仪
    spi_write_reg(REG_FIFO_EN, 0x70);    // GYRO_XOUT, GYRO_YOUT, GYRO_ZOUT
    
    // 设置水印为30帧(30 * 6字节 = 180字节)
    spi_write_reg(REG_FIFO_WM_TH, 30);   // 水印值
}

// 读取FIFO数据
void fifo_read_data(uint8_t *buffer, uint16_t count) {
    uint16_t fifo_count;
    
    // 先读FIFO中还有多少数据
    fifo_count = spi_read_reg(REG_FIFO_COUNT_H) << 8;
    fifo_count |= spi_read_reg(REG_FIFO_COUNT_L);
    
    if (fifo_count >= count) {
        // 一次性读出所有数据
        spi_read_burst(REG_FIFO_R_W, buffer, count);
    }
}
⚠️ 注意:FIFO读空后,不要再读。否则读出来的数据是上次的残留值,会造成数据重复。我踩过这个坑,调试时发现数据波形有「鬼影」,就是FIFO读空后没处理。

4.6 本章知识体系

下面这张图,是我画的数据采集整体流程。你照着这个走,基本不会出大问题:

陀螺仪数据采集流程 1. 初始化配置 复位 → 电源 → 量程 → 滤波 2. 采样率设置 分频系数 → 实际采样率 3. FIFO配置 使能 → 选择数据 → 水印 4. 读取原始数据 连续读取6字节 → 拼合 5. 数据校验 范围检查 → 突变检测 6. 输出有效数据 转物理单位 → 送算法 循环采集(持续运行) 异常处理:数据校验失败 → 丢弃当前帧 → 记录错误计数 → 连续失败则复位 我曾经遇到过SPI线接触不良,导致连续丢帧,最后加了硬件看门狗才解决

嗯,数据采集这块,说白了就是「配置好、读得对、验得准」。每一步都有坑,但只要你按照这个流程走,基本能稳。

下一节咱们会聊陀螺仪数据的预处理,包括去噪和温漂补偿。到时候我会分享一个我调了三个月的温漂补偿算法,保证让你少走弯路。


专注资料整理