You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32读取加速度计FIFO数据时X轴异常,仅最后一个值正确

问题描述

基于ESP32的Platformio Arduino框架,用C/C++编写加速度计FIFO数据读取代码,通过多组函数获取三轴FIFO数据。执行Read_FIFO_packet_16_IIM读取128个数据后,Y、Z轴数据正常(Y约0,Z约1),但X轴数据损坏,每次调用得到固定随机值(预期约0),仅X缓冲的最后一个元素(第128个)数据正确。怀疑是地址指针问题,但同逻辑下Y、Z轴正常,寻求原因及解决方法。

相关代码:

void Get_FIFO_data_16(SPIClass *dev, uint8_t *header, int16_t *payload, uint16_t *timestamp) {
    const uint8_t packet_length = 16; //bytes
    uint8_t packet[packet_length] = {0};
      
    ReadRegBytes(dev, FIFO_DATA, packet, packet_length);
      
    *header = packet[0]; //header
    *payload = packet[1]<<8 | packet[2]; //acc X data
    
    //Serial.println(*payload);

    *(payload + 1) = packet[3]<<8 | packet[4]; //acc Y data
    
    //Serial.println(*(payload + 1));

    *(payload + 2) = packet[5]<<8 | packet[6]; //acc Z data
    *timestamp = packet[14]<<8 | packet[15];
  }


void Read_FIFO16_packet(int16_t* X_data, int16_t* Y_data, int16_t* Z_data, uint16_t *timestamp) {
  uint8_t header = 0;
  int16_t data[3] = {0};
  uint16_t TimeStamp = 0;

  iim_acc_obj.Get_FIFO_data_16(spi_device, &header, data, &TimeStamp);
    /*Header*/

    /********/
  *X_data = data[0]; //X_data is still correct
  *Y_data = data[1];
  *Z_data = data[2];

  *timestamp = TimeStamp;
}


void Read_FIFO_packet_16_IIM (int16_t *X_buffer, int16_t *Y_buffer, int16_t *Z_buffer, uint16_t *timestamp, uint16_t elements_to_read) {
  if (iim_acc_obj.Check_Who_am_I(spi_device) == true) {

    for (int i = 0; i < elements_to_read; i++) {
      Read_FIFO16_packet(X_buffer + i, Y_buffer + i, Z_buffer + i, timestamp + i);

      //Serial.println(*(X_buffer + i)/ 4095.00); //reading like this prints correct value
    }

  } else Serial.print("SPI Coms failed !");    
}


void Print_FIFO_Content_IIM(int16_t *X_data_buff, int16_t *Y_data_buff, int16_t *Z_data_buff, uint16_t *timestamp, uint32_t FIFO_len) {

  Serial.println("Timestamp    X data   Y data  Z data");
  int i = 0;

  for (uint32_t i = 0; i < FIFO_len; i++) {
    Serial.print(*(X_data_buff + i) / 4095.00);  //wrong data
    Serial.print("       ");
    Serial.print(*(Y_data_buff + i) / 4095.00); //correct data
    Serial.print("       ");
    Serial.print(*(Z_data_buff + i) / 4095.00); //correct data
    Serial.print("\n\r");
  }
  memset(X_data_buff, 0, sizeof(X_data_buff));  //reset buffer
  memset(Y_data_buff, 0, sizeof(Y_data_buff));  //reset buffer
  memset(Z_data_buff, 0, sizeof(Z_data_buff));  //reset buffer
}


///main.c///
 int16_t x_data[128] = {0};
 int16_t y_data[128] = {0};
 int16_t z_data[128] = {0};
...
...
Read_FIFO_packet_16_IIM(x_data, y_data, z_data, &timestamp, 128);
Print_FIFO_Content_IIM(x_data, y_data, z_data, &timestamp, 128);
原因定位

问题核心出在Print_FIFO_Content_IIM函数的memset调用:

memset(X_data_buff, 0, sizeof(X_data_buff));

当数组以指针形式传入函数时,sizeof(X_data_buff)获取的是指针本身的大小(ESP32平台为4字节),而非数组的总字节数。这会导致:

  • X缓冲仅被清零前2个int16_t元素(4字节 = 2 * 2字节)
  • 后续循环读取时,新的X数据覆盖前面位置,但旧数据残留加上指针操作的连锁影响,最终只有最后一个元素能保持正确值
  • Y、Z轴看似正常是巧合,实际它们的缓冲也未被正确清零,只是未表现出明显异常

另外,Read_FIFO_packet_16_IIM内的调试代码能正确打印X数据,是因为数据刚写入还未被错误的memset破坏,第一次打印后缓冲被部分清零,后续读取就会出现异常。

解决方法
  1. 修正memset的长度计算
    放弃依赖指针的sizeof,直接通过元素个数计算数组总字节数,修改Print_FIFO_Content_IIM函数:

    void Print_FIFO_Content_IIM(int16_t *X_data_buff, int16_t *Y_data_buff, int16_t *Z_data_buff, uint16_t *timestamp, uint32_t FIFO_len) {
    
      Serial.println("Timestamp    X data   Y data  Z data");
    
      for (uint32_t i = 0; i < FIFO_len; i++) {
        Serial.print(*(X_data_buff + i) / 4095.00);
        Serial.print("       ");
        Serial.print(*(Y_data_buff + i) / 4095.00);
        Serial.print("       ");
        Serial.print(*(Z_data_buff + i) / 4095.00);
        Serial.print("\n\r");
      }
      // 用元素个数 × 单个元素字节数计算总长度
      memset(X_data_buff, 0, FIFO_len * sizeof(int16_t));
      memset(Y_data_buff, 0, FIFO_len * sizeof(int16_t));
      memset(Z_data_buff, 0, FIFO_len * sizeof(int16_t));
    }
    
  2. 验证SPI读取字节序(可选)
    虽然Y、Z轴正常,但可确认加速度计的字节序是否与代码匹配。若设备为小端模式,X数据的拼接逻辑需调整:

    // 原X数据代码
    *payload = packet[1]<<8 | packet[2];
    // 小端模式下修改为
    // *payload = packet[2]<<8 | packet[1];
    
  3. 简化指针传递逻辑(可选)
    减少多层指针嵌套调用,降低出错概率,直接在Read_FIFO_packet_16_IIM中调用Get_FIFO_data_16:

    void Read_FIFO_packet_16_IIM (int16_t *X_buffer, int16_t *Y_buffer, int16_t *Z_buffer, uint16_t *timestamp, uint16_t elements_to_read) {
      if (iim_acc_obj.Check_Who_am_I(spi_device) == true) {
        uint8_t header = 0;
        int16_t data[3] = {0};
        uint16_t TimeStamp = 0;
    
        for (int i = 0; i < elements_to_read; i++) {
          iim_acc_obj.Get_FIFO_data_16(spi_device, &header, data, &TimeStamp);
          X_buffer[i] = data[0];
          Y_buffer[i] = data[1];
          Z_buffer[i] = data[2];
          timestamp[i] = TimeStamp;
        }
      } else Serial.print("SPI Coms failed !");    
    }
    

内容的提问来源于stack exchange,提问作者Dominykas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 17:18:12