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, ×tamp, 128); Print_FIFO_Content_IIM(x_data, y_data, z_data, ×tamp, 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破坏,第一次打印后缓冲被部分清零,后续读取就会出现异常。
解决方法
修正
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)); }验证SPI读取字节序(可选)
虽然Y、Z轴正常,但可确认加速度计的字节序是否与代码匹配。若设备为小端模式,X数据的拼接逻辑需调整:// 原X数据代码 *payload = packet[1]<<8 | packet[2]; // 小端模式下修改为 // *payload = packet[2]<<8 | packet[1];简化指针传递逻辑(可选)
减少多层指针嵌套调用,降低出错概率,直接在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
相关产品推荐
相关产品推荐

