如何通过I2C使用ESP8266接收float数组?
解决ESP8266通过I2C接收float数组的问题
你的代码存在的关键问题
- 在
receiveEvent中断回调中循环调用Wire.readBytes读取单个float,中断上下文的限制可能导致读取不完整 - 直接通过
*(float *)bytes强制类型转换存在内存对齐风险,部分MCU会因此出现解析错误 - 未处理字节序(大端/小端)差异,若发送端与ESP8266字节序不一致,解析结果会完全错误
修正后的完整实现
1. 全局变量与初始化
先确保全局变量和I2C初始化逻辑正确:
#include <Wire.h> #define ARRAY_LENGTH 3 // 根据实际需求调整数组长度 float floatArray[ARRAY_LENGTH]; void setup() { Serial.begin(115200); Wire.begin(0x08); // 设置ESP8266为I2C从机,地址0x08(可自定义) Wire.onReceive(receiveEvent); // 注册接收回调函数 } void loop() { // 主循环无需额外操作,接收逻辑由回调处理 }
2. 修正后的接收回调函数
void receiveEvent(int byteCount) { const int expectedBytes = ARRAY_LENGTH * sizeof(float); // 校验接收字节数是否符合预期 if (byteCount != expectedBytes) { Serial.printf("Error: Received %d bytes, expected %d\n", byteCount, expectedBytes); // 清空I2C缓冲区,避免残留数据影响下一次接收 while (Wire.available()) Wire.read(); return; } // 一次性读取所有字节到临时缓冲区 byte buffer[expectedBytes]; int bytesRead = Wire.readBytes(buffer, expectedBytes); // 确认读取完整度 if (bytesRead != expectedBytes) { Serial.println("Error: Failed to read all data"); return; } // 使用union安全转换字节数组到float,同时处理字节序 for (int i = 0; i < ARRAY_LENGTH; i++) { byte* floatBytes = &buffer[i * sizeof(float)]; // 用union避免内存对齐问题 union { byte b[4]; float f; } floatUnion; // ESP8266为小端架构,若发送端是小端则直接按顺序赋值 floatUnion.b[0] = floatBytes[0]; floatUnion.b[1] = floatBytes[1]; floatUnion.b[2] = floatBytes[2]; floatUnion.b[3] = floatBytes[3]; floatArray[i] = floatUnion.f; Serial.printf("Received float %d: %.1f\n", i, floatArray[i]); } }
核心注意事项
- 字节序匹配:如果发送端是大端架构(如部分STM32设备),需反转字节顺序赋值:
floatUnion.b[0] = floatBytes[3]; floatUnion.b[1] = floatBytes[2]; floatUnion.b[2] = floatBytes[1]; floatUnion.b[3] = floatBytes[0]; - I2C地址一致:确保发送端使用的I2C地址与
Wire.begin(0x08)中的地址完全相同 - 缓冲区清空:接收字节数不符时必须清空缓冲区,防止残留数据干扰后续接收
内容的提问来源于stack exchange,提问作者Fga
相关产品推荐
相关产品推荐

