ADXL375冲击阈值误触发及冲击时轴数据获取问题
问题:ADXL375触发中断后无法获取冲击时的XYZ数值
我用I2C连接ADXL375和Arduino UNO,校准后水平放置时X≈0g、Y≈0g、Z≈1g。已启用触发模式,中断映射到INT2,冲击阈值设为0x28(对应31.2g)。轻敲模块时,中断会触发,但读取的XYZ数值仍在0/0/1g左右,倾斜时数值正常变化(不超3g)。如何获取冲击发生时的XYZ数值?问题出在哪?
寄存器配置代码
/*START Set Shock Threshold*/ Wire.beginTransmission(Device_Address); Wire.write(0x1D); //Shock Duration Register Address Wire.write(0x28); //Scale Factor is 780mg/LSB, hence 0x28 = 31.2g Wire.endTransmission(); /*END Set Shock Threshold*/ /*START Set DUR Thresh_SHOCK*/ //Used for Double Shock Detection Only** Wire.beginTransmission(Device_Address); Wire.write(0x21); //Shock Duration Register Address Wire.write(0x50); //Scale Factor is 625us/LSB, hence 0x50 = 50ms Wire.endTransmission(); /*END Set DUR Thresh_SHOCK*/ /*START Set Latency*/ Wire.beginTransmission(Device_Address); Wire.write(0x22); //Latent Register Address Wire.write(0x20); //Scale Factor is 1.25ms/LSB, hence 0x20 = 400ms Wire.endTransmission(); /*END Set Latency*/ /*START Set Shock Window to 300ms*/ Wire.beginTransmission(Device_Address); Wire.write(0x23); //Window Register Address Wire.write(0xF0); //Scale Factor is 1.25ms/LSB, hence 0xF0 = 300ms Wire.endTransmission(); /*END Set Shock Window to 300ms*/ /*START Enable XYZ-Axis Shock Detection START*/ Wire.beginTransmission(Device_Address); Wire.write(0x2A); //SHOCK_AXES Register Wire.write(0x07); //Enable SHOCK_X, SHOCK_Y, SHOCK_Z Wire.endTransmission(); /*END Enable XYZ-Axis Shock Detection END*/ /*START Set Out-Data-Rate(ODR) to 3200Hz*/ Wire.beginTransmission(Device_Address); Wire.write(0x2C); //BW_RATE Register Address Wire.write(0x0F); //3200 Hz Output Data Rate Wire.endTransmission(); /*END Set Out-Data-Rate(ODR) to 3200Hz */ /*START Enable Single Shock Interrupt*/ Wire.beginTransmission(Device_Address); Wire.write(0x2E); //INT_Enable Register Address Wire.write(0x40); //Enable single Shock Int Wire.endTransmission(); /*END Enable Single Shock Interrupt*/ /*START Assign Single Shock Interrupt*/ Wire.beginTransmission(Device_Address); Wire.write(0x2F); //INT_Map Register Address Wire.write(0x40); //Assign single Shock Int Wire.endTransmission(); /*END Assign Single Shock Interrupt*/ /*START Data Format*/ Wire.beginTransmission(Device_Address); Wire.write(0x31); //DATA_FORMAT Reg Wire.write(0x0B); Wire.endTransmission(); /*END Data Format*/ /*START Enable Trigger Mode*/ Wire.beginTransmission(Device_Address); Wire.write(0x38); //FIFO_CTL Register Address Wire.write(0xEA); //Enable Trigger Mode, set samples = 10 Wire.endTransmission(); /*END Enable Trigger Mode*/ /*START Offset Calibration*/ // Scale Factor = 0.196g/MSB Wire.beginTransmission(Device_Address); Wire.write(0x1E); //OFSX Address Wire.write(0xFA); //OFSX offset Wire.endTransmission(); Wire.beginTransmission(Device_Address); Wire.write(0x1F); //OFSY Address Wire.write(0xFB); //OFSY offset Wire.endTransmission(); Wire.beginTransmission(Device_Address); Wire.write(0x20); //OFSZ Address Wire.write(0xFF); //OFSZ offset Wire.endTransmission(); /*END Offset Calibration*/ /*Start Enable Measuring*/ Wire.beginTransmission(Device_Address); Wire.write(0x2D); //POWER_CTL Register Wire.write(0x08); //Enable Measuring Wire.endTransmission(); /*END Enable Measuring*/ /*Attach Interrupt to Digital pin 2*/ attachInterrupt(digitalPinToInterrupt(2), ISR_Func, RISING);
数据读取代码
int16_t data_x = 0, data_x_lsb = 0; int16_t data_y = 0, data_y_lsb = 0; int16_t data_z = 0, data_z_lsb = 0; Wire.beginTransmission(Device_Address); Wire.write(0x32); //read LSB Wire.endTransmission(); Wire.requestFrom(Device_Address, 6); while (Wire.available()) { data_x_lsb = Wire.read(); data_x = Wire.read(); data_y_lsb = Wire.read(); data_y = Wire.read(); data_z_lsb = Wire.read(); data_z = Wire.read(); data_x = (data_x << 8) | (data_x_lsb); data_y = (data_y << 8) | (data_y_lsb); data_z = (data_z << 8) | (data_z_lsb); } data_x = (double)data_x*49/1000 data_y = (double)data_y*49/1000 data_z = (double)data_z*49/1000
示例输出
14:36:51.120 -> -0.072 -0.067 0.977 14:36:51.221 -> -0.087 -0.096 0.949 14:36:51.325 -> 0.010 -0.191 0.988 14:36:51.427 -> -0.062 -0.162 1.071 14:36:51.536 -> -0.010 -0.088 1.071 14:36:51.614 -> -0.015 -0.037 1.052 14:36:51.725 -> -0.022 -0.047 1.044 14:36:51.837 -> 0.062 -0.043 1.012 14:36:52.025 -> FIFO STATUS REG: A0 14:36:52.025 -> Shock Occured 14:36:52.062 -> ACT STATUS SHOCK REG: 1 14:36:52.062 -> INT_SOURCE: C3 14:36:52.137 -> 0.055 -0.081 0.997 14:36:52.252 -> 0.024 0.031 1.033 14:36:52.354 -> 0.011 -0.072 1.079 14:36:52.455 -> 0.022 -0.031 0.973 14:36:52.547 -> 0.014 -0.042 1.041 14:36:52.654 -> -0.062 -0.036 1.018 14:36:52.770 -> -0.080 -0.003 1.003 14:36:52.880 -> -0.081 -0.118 1.084 14:36:52.972 -> -0.080 -0.039 1.046 14:36:53.079 -> -0.109 -0.016 0
问题分析与修复方案
核心问题
- 触发模式下读取逻辑错误:你配置了FIFO触发模式,但当前代码直接读取实时数据寄存器,而非FIFO中缓存的触发时刻样本,自然拿不到冲击峰值。
- 单冲击持续时间未配置:你仅设置了双冲击的DUR寄存器(0x21),但单冲击的持续时间阈值寄存器(0x20)未配置,导致轻微震动就触发31.2g阈值。
- 量程配置错误:
DATA_FORMAT设为0x0B(±16g),但ADXL375是高g传感器,超过16g的数据会被截断,无法显示真实冲击值。
修复步骤
1. 配置单冲击持续时间阈值
添加单冲击持续时间寄存器配置,避免误触发:
/*START Set Single Shock Duration Threshold*/ Wire.beginTransmission(Device_Address); Wire.write(0x20); // SHOCK_DUR寄存器地址(单冲击专用) Wire.write(0x01); // 625μs/LSB,只有超过阈值且持续625μs才触发 Wire.endTransmission(); /*END Set Single Shock Duration Threshold*/
2. 修正量程配置
将DATA_FORMAT改为±200g量程,支持高g值读取:
/*START Data Format*/ Wire.beginTransmission(Device_Address); Wire.write(0x31); // DATA_FORMAT Reg Wire.write(0x0F); // ±200g量程,全分辨率 Wire.endTransmission(); /*END Data Format*/
3. 正确读取FIFO中的触发样本
触发模式下,FIFO会缓存触发前后的10个样本,需读取FIFO寄存器获取数据:
volatile bool shock_detected = false; void ISR_Func() { shock_detected = true; } void readFIFOSamples() { // 读取FIFO中的10个样本 Wire.beginTransmission(Device_Address); Wire.write(0x30); // FIFO_DATA寄存器地址 Wire.endTransmission(); Wire.requestFrom(Device_Address, 60); // 10个样本×6字节(XYZ各2字节) int sample_count = 0; while (Wire.available() && sample_count < 10) { int16_t x = (Wire.read() | (Wire.read() << 8)); int16_t y = (Wire.read() | (Wire.read() << 8)); int16_t z = (Wire.read() | (Wire.read() << 8)); double g_x = x * 0.049; // ±200g量程下分辨率为49mg/LSB double g_y = y * 0.049; double g_z = z * 0.049; Serial.print("样本"); Serial.print(sample_count+1); Serial.print(": "); Serial.print(g_x); Serial.print("\t"); Serial.print(g_y); Serial.print("\t"); Serial.println(g_z); sample_count++; } // 重置FIFO触发模式 Wire.beginTransmission(Device_Address); Wire.write(0x38); // FIFO_CTL寄存器 Wire.write(0xEA); // 重新启用触发模式 Wire.endTransmission(); // 清除中断标志 Wire.beginTransmission(Device_Address); Wire.write(0x30); // 读取INT_SOURCE寄存器清除标志 Wire.endTransmission(); Wire.requestFrom(Device_Address, 1); Wire.read(); } void loop() { if (shock_detected) { shock_detected = false; Serial.println("Shock Occured"); readFIFOSamples(); } }
4. 优化通信与滤波
- 在
Wire.begin()后添加Wire.setClock(400000);,启用I2C快速模式,提升读取速度。 - 冲击样本读取时关闭移动平均滤波,避免峰值被平滑掩盖。
内容的提问来源于stack exchange,提问作者Diracx
相关产品推荐
相关产品推荐

