ADXL345是一款低功耗,三轴MEMS加速度计模块,具有I2C和SPI接口。这些模块的Adafruit Breakout板载板载3.3v电压调节和电平转换功能,使其易于与Arduino等5v微控制器接口。
ADXL345具有4个灵敏度范围,从+/- 2G到+/- 16G。它支持10Hz到3200Hz的输出数据速率。
工作原理:
MEMS-微型机电系统传感器由硅晶片上的微机械结构组成。该结构由多晶硅弹簧悬挂,当在X,Y和/或Z轴上受到加速度时,它可以在任何方向上平滑偏转。挠曲会导致固定板和连接到悬挂结构的板之间的电容发生变化。每个轴上的电容变化都会转换为与该轴上的加速度成比例的输出电压。
I2C接线: ADXL345分支的I2C地址为0x53。只要每个设备具有唯一的地址,它就可以与其他I2C设备共享I2C总线。
- 超低功耗:在 V S = 2.5 V(典型值)时,测量模式下低至 23 μA,待机模式下低至 0.1 μA
- 功耗随带宽自动扩展
- 用户可选择的分辨率
①固定 10 位分辨率
②全分辨率,其中分辨率随g范围增加,在 ±16 g时分辨率高达 13 位(在所有g范围内保持 4 mg/LSB 比例因子)
ADXL345 是一款小型、薄型、低功耗、3 轴加速度计,具有高达 ±16 g的高分辨率(13 位)测量值。数字输出数据格式为 16 位二进制补码,可通过 SPI(3 线或 4 线)或 I 2 C 数字接口访问。
ADXL345 非常适合移动设备应用。它测量倾斜感应应用中的静态重力加速度,以及运动或冲击产生的动态加速度。其高分辨率 (4 m g /LSB) 可以测量小于 1.0° 的倾角变化。
提供了几种特殊的传感功能。活动和不活动感应检测运动的存在或缺乏,以及任何轴上的加速度是否超过用户设置的水平。轻敲感应检测单击和双击。自由落体感应检测设备是否正在下降。这些功能可以映射到两个中断输出引脚之一。一个集成的、正在申请专利的 32 级先进先出 (FIFO) 缓冲器可用于存储数据,以最大限度地减少主机处理器干预。
低功耗模式支持基于运动的智能电源管理,具有阈值感应和主动加速度测量功能,功耗极低。
ADXL345 采用小型、薄、3 mm × 5 mm × 1 mm、14 引脚塑料封装。
ADXL345-EP 支持国防和航空航天应用 (AQEC)
#ifndef __G_SENSOR_CORE_H
#define __G_SENSOR_CORE_H
#include <stdint.h>
#include <stdbool.h>
#include "bsp_i2c.h"
typedef struct
{
bsp_i2c_bus_t i2c_bus;
uint8_t dev_addr; // 8bit addr
}g_sensor_cfg_t;
bool g_sensor_get_version(void);
bool g_sensor_get_data(short *x, short *y, short *z);
bool g_sensor_set_offset(short *x, short *y, short *z);
void g_sensor_open_sample(void);
void g_sensor_irq_trigger_para(uint8_t activity_val, uint8_t activity_time_ms,
uint8_t static_val, uint8_t static_time_s, uint8_t axis);
void g_sensor_enter_sleep(void);
void g_sensor_set_low_power_awaken(void);
#endif
#ifndef __ADXL34X_H
#define __ADXL34X_H
/* -----------------------------------------头文件-----------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
/* -----------------------------------------宏定义-----------------------------------------*/
#define REG_DEVICE_ID 0X00 // 器件ID 0xE5
#define REG_THRESH_TAP 0X1D // 敲击阈值
#define REG_OFSX 0X1E // X轴偏移
#define REG_OFSY 0X1F // Y轴偏移
#define REG_OFSZ 0X20 // Z轴偏移
#define REG_DUR 0X21
#define REG_LATENT 0X22
#define REG_WINDOW 0X23
#define REG_THRESH_ACT 0X24
#define REG_THRESH_INACT 0X25
#define REG_TIME_INACT 0X26
#define REG_ACT_INACT_CTL 0X27
#define REG_THRESH_FF 0X28
#define REG_TIME_FF 0X29
#define REG_TAP_AXES 0X2A
#define REG_ACT_TAP_STATUS 0X2B
#define REG_BW_RATE 0X2C
#define REG_DATAX0 0X32
/*
* 寄存器0x32至0x37—DATAX0、DATAX1、DATAY0、DATAY1、DATAZ0和DATAZ1(只读)
* 输出数据为二进制补码,DATAx0为最低有效字节,DATAx1为最高有效字节
*/
/*
* POWER_CTL(读/写)
D7 D6 D5 D4 D3 D2 D1 D0
0 0 Link AUTO_SLEEP Measure Sleep Wakeup
休眠模式下的读取频率
设置
D1 D0 频率(Hz)
0 0 8
0 1 4
1 0 2
1 1 1
*/
#define REG_POWER_CTL 0X2D
#define REG_INT_ENABLE 0X2E
#define REG_INT_MAP 0X2F
#define REG_INT_SOURCE 0X30
/*
* SELF_TEST位设置为1时,自测力作用于传感器,造成输出
数据转换。值为0时,禁用自测力。
D7 D6 D5 D4 D3 D2 D1 D0
SELF_TEST SPI INT_INVERT 0 FULL_RES Justify Range
SELF_TEST位:设置为1时,自测力作用于传感器,造成输出数据转换。
值为0时,禁用自测力。
INT_INVERT位:值为0时,将中断设为高电平有效;值为1时,
则将中断设为低电平有效。
FULL_RES位:当此位值设置为1时,该器件为全分辨率模式,输出分辨
率随着范围位设置的g范围以4 mg/LSB的比例因子而增加。
D1 D0 g范围
0 0 ±2g
0 1 ±4g
1 0 ±4g
1 1 ±16g
*/
#define REG_DATA_FORMAT 0X31
#define REG_DATA_X0 0X32
#define REG_DATA_X1 0X33
#define REG_DATA_Y0 0X34
#define REG_DATA_Y1 0X35
#define REG_DATA_Z0 0X36
#define REG_DATA_Z1 0X37
#define REG_FIFO_CTL 0X38
#define REG_FIFO_STATUS 0X39
#define REG_ADXL_READ 0X3B
#define REG_ADXL_WRITE 0X3A
#endif
/********************************************************************************
* @file g_sensor_core.c
* @author jianqiang.xue
* @Version V1.0.0
* @Date 2021-08-21
* @brief 参考: http://blog.sina.com.cn/s/blog_17029604f0102wxtp.html
[校准原理]
首先,这个校准的过程是手动的(类似手机上的传感器校准),把模块水平放置(这个水平也只是个大概,如果要求高的话,还需要其他仪器辅助),
那么x轴和y轴的度数应该为0g,
获取此时的实际x轴和y轴的度数,假设是20和-17。
要注意此时传感器的量程和分辨率,假设此时adxl345是常规量程 -16g,分辨率13位,
那么此时度数的系数应该是1g/256 *1000 = 3.9 mg/LSB,(手册第三页数据表)
从数据手册上可以查到 偏移寄存器的比例因子是 15.6mg/LSB(固定的,与量程无关)
那么需要设定的实际偏移值就是 20/4 = 5和-17/4 = 4(15.6/3.9约为4)
然后取两个值的补码,分别为0x05和0xFB,写入对应的偏移寄存器。
这样,每次从传感器读取的数值就自动加上了这个设置的偏移。
z轴的偏移值检测方式一样,把z轴水平放置(处于0g场)。
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "bsp_i2c.h"
/* Private includes ----------------------------------------------------------*/
#include "g_sensor_core.h"
#include "adxl34x.h"
#include "log.h"
/* Private define ------------------------------------------------------------*/
#define ADXL345_DEVICE_ID 0XE5
#define ADXL346_DEVICE_ID 0XE6
/* Private typedef -----------------------------------------------------------*/
static const g_sensor_cfg_t g_sensor_info =
{
.i2c_bus = I2C_BUS0,
.dev_addr = 0xA6,
};
uint8_t device_version = 0; // 记录传感器版本
uint8_t ret = 0;
uint8_t xyx_data[6] = {0};
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Public function prototypes -----------------------------------------------*/
static uint8_t i2c_read_byte(uint8_t reg_addr, uint8_t *r_data)
{
return bsp_i2c_read_byte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
reg_addr, r_data);
}
static uint8_t i2c_read_nbyte(uint8_t reg_addr, uint8_t *r_data, uint8_t r_len)
{
return bsp_i2c_read_nbyte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
®_addr, 1, r_data, r_len);
}
static uint8_t i2c_write_byte(uint8_t reg_addr, uint8_t w_data)
{
return bsp_i2c_write_byte(g_sensor_info.i2c_bus, g_sensor_info.dev_addr,
reg_addr, w_data);
}
/**
* @brief 读取传感器版本,用于判断器件是否可用
* @note NULL
* @retval 0--失败 1--成功
*/
bool g_sensor_get_version(void)
{
i2c_read_byte(REG_DEVICE_ID, &device_version);
//LOG_D("ADXL:0x%02x\r\n", device_id_val);
if (device_version != ADXL345_DEVICE_ID && device_version != ADXL346_DEVICE_ID)
{
return false;
}
return true;
}
/**
* @brief 设置活动/静止时的值,和哪三轴可以触发中断
* @note NULL
* @param activity_val: 活动阈值 变化幅度
* @param activity_time_ms: 活动阈值时间 单位:ms
* @param static_val: 静止阈值 变化幅度
* @param static_time_s: 静止时间 单位:s
* @param axis:
* * [7bit] 活动检测 0--直接REG_THRESH_ACT比较 1--相对值达到REG_THRESH_ACT
* * [6bit] X_EN [5bit] Y_EN [4bit] Z_EN
* * [3bit] 静止检测 0--直接REG_THRESH_INACT比较 1--相对值达到REG_THRESH_INACT
* * [2bit] X_EN [1bit] Y_EN [0bit] Z_EN
* @retval None
*/
void g_sensor_irq_trigger_para(uint8_t activity_val, uint8_t activity_time_ms,
uint8_t static_val, uint8_t static_time_s, uint8_t axis)
{
// 活动阈值 变化幅度
i2c_write_byte(REG_THRESH_ACT, activity_val);
// 活动阈值时间 单位:ms
i2c_write_byte(REG_DUR, activity_time_ms);
// 静止阈值
i2c_write_byte(REG_THRESH_INACT, static_val);
// 静止时间 单位:s
i2c_write_byte(REG_TIME_INACT, static_time_s);
// 活动静止任意轴选择 选择三轴使能
i2c_write_byte(REG_ACT_INACT_CTL, axis);
}
/**
* @brief 传感器进入睡眠状态,如果之前配置了中断,那么就会清除中断功能
* @note 如果想要中断唤醒,则先使用本函数,再调用g_sensor_set_low_power_awaken
* @retval None
*/
void g_sensor_enter_sleep(void)
{
// 中断清零前,应读取ACT_TAP_STATUS寄存器
i2c_read_byte(REG_ACT_TAP_STATUS, &ret);
// 读取中断标志寄存器,读一次清空一次中断标记
i2c_read_byte(REG_INT_SOURCE, &ret);
// 禁用 中断功能
i2c_write_byte(REG_INT_ENABLE, 0x00);
// 设置时需进入休眠模式 1HZ采集一次
i2c_write_byte(REG_POWER_CTL, 0x01);
}
/**
* @brief 配置加速度传感器,活动触发中断(用于低功耗唤醒),需要先配置g_sensor_irq_trigger_para
* @note NULL
* @retval None
*/
void g_sensor_set_low_power_awaken(void)
{
g_sensor_enter_sleep();
// 使能 中断 ININ1
i2c_write_byte(REG_INT_MAP, 0x00);
// 寄存器0x31—DATA_FORMAT(读/写)--中断设为高电平有效--全分辨率模式--右对齐模式--+16g
i2c_write_byte(REG_DATA_FORMAT, 0x0B);
i2c_write_byte(REG_INT_ENABLE, 0x10); // 开启动态中断模式,19页
}
/**
* @brief 传感器开始工作采集[FIFO流模式]
* @note 流程:设置流模式--进入待机状态--进入测试状态
* @retval None
*/
void g_sensor_open_sample(void)
{
// FIFO流模式 将触发模式下的触发事件链接至INT2(这个中断脚没有使用)
i2c_write_byte(REG_FIFO_CTL, 0xA8);
// 待机模式
i2c_write_byte(REG_POWER_CTL, 0x00);
// 测量模式
i2c_write_byte(REG_POWER_CTL, 0x08);
}
/**
* @brief 读取一次传感器值
* @note NULL
* @retval 0--失败 1--成功
*/
bool g_sensor_get_data(short *x, short *y, short *z)
{
if (i2c_read_nbyte(REG_DATAX0, xyx_data, 6) != 0)
{
return false;
}
*x = xyx_data[1] << 8 | xyx_data[0];
*y = xyx_data[3] << 8 | xyx_data[2];
*z = xyx_data[5] << 8 | xyx_data[4];
return true;
}
/**
* @brief 设置传感器offset值(一次性,器件掉电或重启需要重新设置)
* @note -16g,分辨率13位,系数应该是1g/256 *1000 = 3.9 mg/LSB,(手册第三页数据表)
偏移寄存器的比例因子是 15.6mg/LSB(固定的,与量程无关) 那么需要设定的实际偏移值就是 x/4(15.6/3.9约为4)
* @retval 0--失败 1--成功
*/
bool g_sensor_set_offset(short *x, short *y, short *z)
{
// 设置X轴偏移量
i2c_write_byte(REG_OFSX, (char)(-(*x / 4)));
// 设置Y轴偏移量
i2c_write_byte(REG_OFSY, (char)(-(*y / 4)));
// 设置Z轴偏移量
i2c_write_byte(REG_OFSZ, (char)(-(*z / 4)));
return true;
}