ESP32读取ADXL345无法获取负值的技术求助
解决ESP32上ADXL345无法读取负值的问题
在Arduino UNO上运行ADXL345的I2C代码可正常获取三轴加速度值(示例输出:0.05 0.10 1.01),但移植到ESP32后,输出变为255.89 255.81 0.99,完全无法读取负值,原始数据示例为65000、65000、1。
问题根源
ADXL345输出的是16位有符号整数(int16_t),但ESP32的Wire.read()返回的是无符号8位整数(uint8_t)。直接拼接高低字节时,高位的符号位会被当作无符号位处理,导致负值被错误转换为大的正值(比如-1会被解析为65535)。而Arduino UNO的Wire.read()返回int类型,会自动处理符号扩展,因此不会出现该问题。
修复方案
修改数据类型定义和字节拼接逻辑,确保符号位正确扩展:
- 将存储原始三轴数据的变量改为
int16_t类型,适配传感器的有符号输出。 - 读取字节时,先将
uint8_t转换为int8_t,再进行位运算,保证符号扩展正确。 - 计算加速度值时,用
int16_t直接除以256.0转换为浮点型。
修改后的完整代码
#include <Wire.h> const int ADXL345 = 0x53; // ADXL345的I2C地址 int16_t X_out, Y_out, Z_out; // 存储原始有符号数据 float X, Y, Z; // 最终加速度值(单位:g) void setup() { Serial.begin(115200); Wire.begin(); // 配置ADXL345数据格式 Wire.beginTransmission(ADXL345); Wire.write(0x31); // 数据格式寄存器 Wire.write(0x0B); Wire.endTransmission(); // Z轴偏移校准 Wire.beginTransmission(ADXL345); Wire.write(0x20); // Z轴偏移寄存器 Wire.write(-7); Wire.endTransmission(); // 开启测量模式 Wire.beginTransmission(ADXL345); Wire.write(0x2D); // 电源控制寄存器 Wire.write(0x08); // 启动测量 Wire.endTransmission(); // 设置输出数据速率 Wire.beginTransmission(ADXL345); Wire.write(0x2C); // 速率控制寄存器 Wire.write(0x09); // 10Hz输出速率 Wire.endTransmission(); delay(10); } void loop() { // 读取加速度数据 Wire.beginTransmission(ADXL345); Wire.write(0x32); // 从X轴高位寄存器开始读取 Wire.endTransmission(false); Wire.requestFrom(ADXL345, 6, true); // 读取6个寄存器(每个轴占2个字节) // 正确拼接高低字节,处理符号扩展 X_out = (static_cast<int8_t>(Wire.read())) | (Wire.read() << 8); Y_out = (static_cast<int8_t>(Wire.read())) | (Wire.read() << 8); Z_out = (static_cast<int8_t>(Wire.read())) | (Wire.read() << 8); // 转换为加速度值(±2g范围下,原始值除以256) X = X_out / 256.0f; Y = Y_out / 256.0f; Z = Z_out / 256.0f; // 输出结果 Serial.print(X); Serial.print(" "); Serial.print(Y); Serial.print(" "); Serial.println(Z); delay(20); }
关键修改说明
X_out、Y_out、Z_out从float改为int16_t,确保存储有符号的原始数据。- 拼接字节时使用
static_cast<int8_t>(Wire.read())将无符号字节转换为有符号字节,这样高位为1的负值会正确扩展符号位。 - 除以256时使用
256.0f确保浮点运算,避免整数除法导致精度丢失。
内容的提问来源于stack exchange,提问作者Tryingtogetsome
相关产品推荐
相关产品推荐

