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

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

问题分析与修复方案

核心问题

  1. 触发模式下读取逻辑错误:你配置了FIFO触发模式,但当前代码直接读取实时数据寄存器,而非FIFO中缓存的触发时刻样本,自然拿不到冲击峰值。
  2. 单冲击持续时间未配置:你仅设置了双冲击的DUR寄存器(0x21),但单冲击的持续时间阈值寄存器(0x20)未配置,导致轻微震动就触发31.2g阈值。
  3. 量程配置错误: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 07:30:43