ADXL362是ADI公司的加速度传感器,这个产品在小米手环里被用到了。它的核心技术是超级低功耗检测运动、加速度、静止这些信息。
它里面有几种模式:
1)默认模式
传感器刚起来时进入默认状态,此时运动和静止的状态是不使能的。如果用户使能了运动和静止功能,静止和运动两种检测皆可以被检测,并且可以触发中断。处理器必须处理中断。
实际将寄存器ACT_INACT_CTL寄存器设置为Default Mode(代码中是ADXL362_MODE_DEFAULT),允许运动和静止检测和中断,但实际上试了不行。
2)Link模式
LINK模式下,运动和静止检测链接在一起。可以配合中断检测。如果需要连续检测运动/静止(可以在中断里查看AWAKE位判断是检测到运动还是静止),这个方法可以。
特别要注意:在中断处理函数处理完后,退出来之前,一定要再读一次ADXL362的STATUS(读取这个STATUS可以把ADXL362内部的中断信息清空),否则有可能出现无法再进中断的危险。这个估计是ADXL362的一个重大bug。但是实际测试发现片子存在不一致性,即有些片子即使在退出中断前再读一次STATUS,仍然还存在无法再进中断的风险。
下面是读取STATUS清空ACT和INACT中断信息的文档中的依据。
3)LOOP模式
LOOP模式和LINK模式很像。文档资料里说不需要中断服务。但实际上是可以用中断一起配合使用的。
但是它的问题和LINK一样,存在永远无法进入中断的问题。这个BUG的现象和LINK一模一样。解决办法是退出来之前,一定要再读一次ADXL362的STATUS(读取这个STATUS可以把ADXL362内部的中断信息清空)。LOOP模式的好处是貌似不存在不一致性,也就是片子的一致性可以。
因此,强烈建议选LOOP模式。
现在解释下这个现象产生的过程(在INT1中断引脚的处理函数里):
void EXTI_IRQHandler()
{
unsigned char adxl362_status = 0;
ADXL362_GetRegisterValue(&adxl362_status, ADXL362_REG_STATUS, 1);
if(adxl362_status & ADXL362_STATUS_AWAKE)
{// 检测到运动
// (A)
}
else
{// 检测到静止
// (B)
}
EXTI->PR = ((uint32_t)0x00000400);
// 下面这句必须添加,以防ADXL362不工作
ADXL362_GetRegisterValue(&adxl362_status, ADXL362_REG_STATUS, 1);//(C)
}
上面的代码是用来不断检测运动和静止的代码。
如果ADXL362检测到静止,然后在处理静止的时候(B)位置(还未退出中断)发生了运动事件(ADXL362在这么短时间内检测到运动了),那么如果没有(C)代码,那么会导致无法在进中断。同样的,如果在检测到运动的时候(A)发生了静止事件(还未退出中断),那么同样的,如果没有(C)代码,会导致后续无法再进中断。
下面是比较好的连续检测静止和运动的初始代码。
void ADXL362(void)
{
unsigned char adxl362_status;
/* Init device. */
if(ADXL362_Init())
{
/* Put the device in standby mode. */
ADXL362_SetPowerMode(0);
/* Set accelerometer's output data rate to: 12.5 Hz. */
ADXL362_SetOutputRate(ADXL362_ODR_12_5_HZ);
/* Setup the activity and inactivity detection. */
ADXL362_SetRegisterValue(
ADXL362_ACT_INACT_CTL_LINKLOOP(ADXL362_MODE_LINK),
ADXL362_REG_ACT_INACT_CTL,
1);
ADXL362_SetupActivityDetection(1, 50, 3); // 检测参考阀值: 200mg, 检测时间: 第三个参数值 / 12.5 s
ADXL362_SetupInactivityDetection(1, 200, 36); // 检测参考阀值: 200mg, 检测时间: 第三个参数值 / 12.5 s
ADXL362_SetRegisterValue(0x30, ADXL362_REG_INTMAP1, 1);
/* Start the measurement process. */
//ADXL362_SetPowerMode(1);
ADXL362_SetRegisterValue(ADXL362_POWER_CTL_MEASURE(ADXL362_MEASURE_ON), ADXL362_REG_POWER_CTL, 1);
/* Clear ACT and INACT bits by reading the Status Register. */
ADXL362_GetRegisterValue(&adxl362_status,
ADXL362_REG_STATUS,
1);
ACCIoInit();
}
}
片子的运动和静止需要设置检测时间,这个检测时间和片子的ODR配置相关。公式是:
Time = TIME_ACT/ODR.
比如上面的代码TIME_ACT是3,选的ODR是12.5Hz,那么检测运动的时间是3/12.5Hz。