STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
目录
- STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
- STC8H开发(四): FwLib_STC8 封装库的介绍和使用注意事项
- STC8H开发(五): SPI驱动nRF24L01无线模块
- STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
- STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
- STC8H开发(九): STC8H8K64U模拟USB HID外设
- STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)
- STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计
ADXL345
ADXL345是一款常见的的3轴加速度计, Analog Device生产. 13位分辨率, ±16 g测量范围, 分辨率3.9 mg/LSB. 可通过SPI(3线或4线)或I2C接口访问.
主要用于倾斜检测, 静态重力加速度测量, 以及运动或冲击导致的动态加速度测量. 能够测量不到1.0°的倾斜角度变化. 可以对单击, 双击, 自由落体等情况设置中断.
模块与STC8H的接线
市面上的模块, 一般是8个pin脚, 在使用SPI接线方式的情况下, 与STC8H的接线方式如下. 除了SPI用到的CS, MISO, MOSI, SCLK以外, STC8H还需要提供两个中断输入, 因为INT0, INT1已经被SPI接口占用, 所以只能用INT2和INT3, 这两个外部中断只支持低电平触发, 所以在ADXL345中需要设置中断输出为active low.
* GND -> GND G
* VDD(Vcc) -> VCC V
* CS -> GPIO OUT P35 34
* INT1 -> GPIO IN P36 INT2 35
* INT2 -> GPIO IN P37 INT3 36
* SDO -> MISO P33 30
* SDI/SDA -> MOSI P34 31
* SCL -> SCLK P32 29
模块与STC8H的SPI通信
SPI的初始化和大多数SPI设备不同, 使用的初始化参数是
- 时钟空闲时高电平
- 数据顺序 MSB 先发送
- 时钟相位上数据使用时钟后沿读取
void SPI_Init(void)
{
// ADXL345, SPI CLK max frequency is 5MHz
SPI_SetClockPrescaler(SPI_ClockPreScaler_16);
// Clock is high when idle
SPI_SetClockPolarity(HAL_State_ON);
// Data transfer is driven by lower SS pin
SPI_SetClockPhase(SPI_ClockPhase_TrailingEdge);
// MSB first
SPI_SetDataOrder(SPI_DataOrder_MSB);
// Define the output pins
SPI_SetPort(SPI_AlterPort_P35_P34_P33_P32);
// Ignore SS pin, use MSTR to swith between master/slave mode
SPI_IgnoreSlaveSelect(HAL_State_ON);
// Master mode
SPI_SetMasterMode(HAL_State_ON);
// Start SPI
SPI_SetEnabled(HAL_State_ON);
}
可以沿用之前多字节发送的接口, 这里需要注意的是
- ADXL345对同一个寄存器地址的写和读, 通过地址的D7(最高位)来区分, 读操作需要将D7置1
- ADXL345支持一次读取多字节, 即burst read, 通过地址的D6(次高位)来区分, 读取多字节时需要将D6置1
uint8_t ADXL345_ReadByte(uint8_t addr)
{
ADXL345_CS = 0;
xbuf[0] = addr | 0x80;
xbuf[1] = 0xFF;
SPI_TxRxBytes(xbuf, 2);
ADXL345_CS = 1;
return xbuf[1];
}
uint16_t ADXL345_ReadInt(uint8_t addr)
{
ADXL345_CS = 0;
xbuf[0] = addr | 0xC0;
xbuf[1] = 0xFF;
xbuf[2] = 0xFF;
SPI_TxRxBytes(xbuf, 3);
ADXL345_CS = 1;
return *((uint16_t *)&xbuf[1]);
}
void ADXL345_WriteByte(uint8_t addr, uint8_t dat)
{
ADXL345_CS = 0;
xbuf[0] = addr;
xbuf[1] = dat;
SPI_TxRxBytes(xbuf, 2);
ADXL345_CS = 1;
}
模块的中断及设置
中断类型
模块提供多种中断, 包含
DATA READY 数据待读取
当三轴数据采集完成时, 会产生这个中断, 采集的速度是由寄存器0x2C—BW_RATE决定的, 默认为100Hz, 即每秒100次采集.
当中断产生后, 必须通过读取X, Y, Z轴的采样数据才能清除中断, 如果没有读取动作, 就不会再产生中断
SINGLE TAP 单次敲击
当采样数据满足预设的敲击加速度和持续时长时, 会产生这个中断, 产生中断后, 必须通过读取中断源寄存器寄存器0x30—INT_SOURCE将中断清除, 否则不会再产生中断.
DOUBLE TAP 双击
同上, 当单次敲击满足预设的时间间隔和时间窗口时, 会产生这个中断, 需要通过读取中断源寄存器将中断清除
ACTIVITY 活动和 INACTIVITY 非活动
加速度值大于THRESH_ACT寄存器(地址0x24)存储值时, Activity(活动)中断置位. 加速度值小于THRESH_INACT寄存器(地址0x25)的存储值时, Inactivity(静止)位置位, TIME_INACT最大值为255秒.
需要通过读取中断源寄存器清除中断
FREE FALL 自由落体
加速度值小于THRESH_FF寄存器(地址0x28)的存储值时, FREE_FALL置位. 大于TIME_FF寄存器(地址0x29)所有轴(逻辑与)所规定的时间.
FREE_FALL中断不同于静止中断, 因为所有轴始终参与, 并为逻辑“和”的形式,定时器周期小得多(最大值 1.28秒), 始终为直流耦合操作模式.
WATERMARK 水位
在FIFO模式和流模式下, FIFO中的采样数与FIFO_CTL寄存器(地址0x38)采样数位规定的数量相等时, 水位中断置位. 此后FIFO继续收集样本直到填满, 然后停止收集数据.
FIFO停止收集数据后, 该器件继续工作, 因此, FIFO填满
时, 敲击检测等功能可以使用
OVERRUN 溢出
当有新采样点更新了未被读取的前次采样点时, Overrun中断置位. Overrun功能与FIFO的工作模式有关:
- 当FIFO工作在Bypass模式下, 如果有新采样点更新了DATAX、
DATAY和DATAZ寄存器(地址0x32至0x37)里的数值,则Overrun中断置位 - 在其他模式下, 只有FIFO被存满时, Overrun中断才会置位.
- 读取FIFO内容时,Overrun位自动清零
中断设置
对应的寄存器有
- 寄存器0x2E—INT_ENABLE 这里设置各个中断的开启和关闭
- 寄存器0x2F—INT_MAP (R/W) 这里设置中断输出到INT1还是INT2, 对应的位为0输出到INT1, 为1输出到INT2
- 寄存器0x30—INT_SOURCE(只读) 产生中断时, 中断对应的位会被置1, 读取这里的值可以判断中断来源并清除中断
敲击检测参数说明
ADXL345的敲击检测和双击检测有5个参数可以设置, 如果设置得不正确, 可能会完全不产生中断
寄存器0x2A—TAP_AXES
用于设置参与检测的轴, 测试阶段可以将三个轴都打开
寄存器0x1D THRESH_TAP
用于设置敲击判断的加速度阈值, 运动时检测到的加速度会与THRESH_TAP的值进行比较, 超过即满足. 需要设置合适的值以便实现正常敲击检测.
从0到255, 间隔为 62.5 mg/LSB(即0xFF = 16 g), 开启敲击检测后这个值不能为0, 否则芯片会不能正常工作.
实际测试中, 值不能太小, 否则一直在触发, 值也不能太大, 否则无论怎么敲击也检测不到中断, 经验值为0x1F到0x35之间, Arduino库使用的是0x28, 对应2.5g加速度.
寄存器0x21 DUR
时间长度值, 运动中, 满足THRESH_TAP加速度强度的采集, 其持续时间与 DUR 的值进行比较, 超过即满足. 需要设置合适的值才能正确检测敲击.
从0到255, 间隔为 625 μs/LSB, 值为0时,禁用单击/双击检测功能.
实际测试中, 值不能太大否则完全检测不到, Arduino库使用的是0x20, 0.02秒, 可以在这个附近调整.
寄存器0x22—Latent
时间长度, 表示在检测到敲击后, 与第二次敲击之间需要满足的间隔长度, 在此间隔时间后开启检测窗口, 能检测出可能的第二次敲击事件.
英文手册的原文 The latent register is eight bits and contains an unsigned time value representing the wait time from the detection of a tap
event to the start of the time window (defined by the window register) during which a possible second tap event can be detected.
从0到255, 间隔为 1.25 ms/LSB, 值为0时,禁用双击检测功能
可以根据自己的场景调整, Arduino库使用的是0x50, 对应0.1秒.
寄存器0x23—Window
时间长度, 表示在延迟时间(由Latent寄存器确定)期满后的时间窗口长度,在窗口中开始进行第二次有效敲击。
从0到255, 间隔为 1.25 ms/LSB, 值为0时,禁用双击检测功能
英文手册原文 The window register is eight bits and contains an unsigned time value representing the amount of time after the expiration of the
latency time (determined by the latent register) during which a second valid tap can begin.
可以根据自己的场景调整, Arduino库使用的是0xF0, 对应0.3秒.
中断使用的注意事项
- 在中断处理中, 要清除中断位
- 在初始化后, 一定要清中断, 否则不会产生第一次中断处理, 就一直卡在哪里
下面这段代码就是在进入main循环前的中断清理
// read to clear interrupts, or the counter will never receive interrupts
x = ADXL345_ReadInt(ADXL345_REG_DATAX0);
y = ADXL345_ReadInt(ADXL345_REG_DATAY0);
z = ADXL345_ReadInt(ADXL345_REG_DATAZ0);
x = ADXL345_ReadByte(ADXL345_REG_INT_SOURCE);
检测数据
ADXL345在检测过程中, 根据采样速率不断输出三轴上采样的加速度值, 因为重力加速度的存在, 在调整模块倾斜度时能观察到读数的变化, 对应PCB上标识的三轴方向, 当轴朝向地面时, 读数会达到最大负值, 在背向地面时, 能读到最大正值. 根据三轴采样到的数据, 可以判断(如果当前是静止状态)器件姿态(倾斜度).
这个采样只能得到俯仰角和横滚角数据, 不能得到航向角数据, 如果需要航向角, 还需要有电子罗盘传感器配合.