Files
99_7018_lmx/apps/earphone/xtell_Sensor/LIS2DH12.c

257 lines
9.9 KiB
C
Raw Normal View History

2025-10-30 11:33:38 +08:00
// LIS2DH12驱动 - 由Kilo Code注释
2025-10-29 16:24:16 +08:00
#include "gSensor/gSensor_manage.h"
#include "app_config.h"
#include "math.h"
#include "LIS2DH12.h"
#include "colorful_lights/colorful_lights.h"
2025-10-30 11:33:38 +08:00
#include <string.h> // 用于 memcpy
2025-10-29 16:24:16 +08:00
#define ENABLE_XLOG 1
#ifdef xlog
#undef xlog
#endif
#if ENABLE_XLOG
#define xlog(format, ...) printf("[%s] " format, __func__, ##__VA_ARGS__)
#else
#define xlog(format, ...) ((void)0)
#endif
2025-10-30 11:33:38 +08:00
// --- 运动检测核心参数 ---
#define SAMPLE_COUNT 6 // 定义静止状态检测所需的样本数量
#define THRESHOLD 50.00f // 定义静止状态检测的阈值(三轴数据方差),值越大,对微小抖动的容忍度越高
#define LPF_ALPHA 0.95f // 低通滤波系数越接近1滤波效果越强重力估算越平滑
#define DEADZONE_MSS 0.2f // 加速度死区阈值 (m/s^2),低于此值的线性加速度被视为噪声并忽略
// --- 原有业务逻辑宏定义 ---
#define STATIC_MAX_TIME 60*5*5 // 传感器静止最大时间,单位 200ms
#define DORMANCY_MAX_TIME 60*5 // 休眠检测时间,单位 200ms
u8 dormancy_flag = 0; // 休眠标识
u8 dormancy_ago_moedl = 0; // 记录休眠前灯效
u16 gsensor_static_flag; // 记录传感器静止的时间,单位 200ms
axis_info_t current_data[32]; // 用于存储从FIFO读取的原始传感器数据
// --- 运动数据全局变量 ---
static motion_data_t motion_data = {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}; // 存储最终计算出的速度和距离
static axis_info_xtell gravity_vector = {0.0f, 0.0f, -GRAVITY_EARTH}; // 存储估算出的重力向量初始假设Z轴朝下
static bool sensor_is_stable = false; // 传感器是否静止的标志
static axis_info_xtell linear_accel_global = {0.0f, 0.0f, 0.0f}; // 存储移除重力后的线性加速度,用于日志打印
static axis_info_xtell zero_g_offset = {0.0f, 0.0f, 0.0f}; // 存储开机校准测得的零点偏移量
2025-10-29 16:24:16 +08:00
u8 gsensor_alarm;
2025-10-30 11:33:38 +08:00
axis_info_xtell gsensor_xtell; // 存储is_sensor_stable计算出的平均值
2025-10-29 16:24:16 +08:00
2025-10-30 11:33:38 +08:00
// --- I2C地址定义 ---
2025-10-29 16:24:16 +08:00
#define LIS2DH12_W_ADDR 0x32
#define LIS2DH12_R_ADDR 0x33
2025-10-30 11:33:38 +08:00
// --- IIC 寄存器地址宏定义 ---
#define LIS2DH12_WHO_AM_I 0x0F
2025-10-29 16:24:16 +08:00
#define LIS2DH12_CTRL_REG1 0x20
#define LIS2DH12_CTRL_REG4 0x23
#define LIS2DH12_CTRL_REG5 0x24
#define LIS2DH12_OUT_X_L 0x28
#define LIS2DH12_FIFO_CTRL_REG 0x2E
#define LIS2DH12_SRC_REG 0x2F
2025-10-30 11:33:38 +08:00
// --- I2C底层函数封装 ---
u32 SL_MEMS_i2cRead(u8 addr, u8 reg, u8 len, u8 *buf) {
2025-10-29 16:24:16 +08:00
return _gravity_sensor_get_ndata(addr, reg, buf, len);
}
2025-10-30 11:33:38 +08:00
u8 SL_MEMS_i2cWrite(u8 addr, u8 reg, u8 data) {
2025-10-29 16:24:16 +08:00
gravity_sensor_command(addr, reg, data);
return 0;
}
2025-10-30 11:33:38 +08:00
// 检查传感器ID确认设备是否正常连接
char LIS2DH12_Check() {
2025-10-29 16:24:16 +08:00
u8 reg_value = 0;
SL_MEMS_i2cRead(LIS2DH12_R_ADDR, LIS2DH12_WHO_AM_I, 1, &reg_value);
if (reg_value == 0x33) {
return 0x01;
}
2025-10-30 11:33:38 +08:00
return 0x00;
2025-10-29 16:24:16 +08:00
}
2025-10-30 11:33:38 +08:00
// 从传感器FIFO读取一批原始数据
void LIS2DH12_read_data(axis_info_t *sl_accel) {
2025-10-29 16:24:16 +08:00
u8 fifo_src = 0;
u8 samples_available = 0;
2025-10-30 11:33:38 +08:00
u8 data[192];
2025-10-29 16:24:16 +08:00
s16 raw_x,raw_y,raw_z;
2025-10-30 11:33:38 +08:00
2025-10-29 16:24:16 +08:00
SL_MEMS_i2cRead(LIS2DH12_R_ADDR, LIS2DH12_SRC_REG, 1, &fifo_src);
2025-10-30 11:33:38 +08:00
samples_available = fifo_src & 0x1F;
if (samples_available == 0) return;
2025-10-29 16:24:16 +08:00
SL_MEMS_i2cRead(LIS2DH12_R_ADDR, LIS2DH12_OUT_X_L | 0x80, samples_available * 6, data);
for (u8 i = 0; i < samples_available; i++) {
2025-10-30 11:33:38 +08:00
// 数据处理方式与 +/-8g 普通模式(10位) 匹配
raw_x = (int16_t)((data[i * 6 + 1] << 8) | data[i * 6]) >> 6;
2025-10-29 16:24:16 +08:00
raw_y = (int16_t)((data[i * 6 + 3] << 8) | data[i * 6 + 2]) >> 6;
raw_z = (int16_t)((data[i * 6 + 5] << 8) | data[i * 6 + 4]) >> 6;
2025-10-30 11:33:38 +08:00
2025-10-29 16:24:16 +08:00
sl_accel[i].x = raw_x;
sl_accel[i].y = raw_y;
sl_accel[i].z = raw_z;
}
}
2025-10-30 11:33:38 +08:00
// 开机校准函数:测量传感器的静态零点偏移
void LIS2DH12_calibrate() {
xlog("开始传感器校准...\n");
axis_info_t cal_data[32];
long x_sum = 0, y_sum = 0;
const int num_samples = 32;
delay_2ms(100); // 等待约200ms让FIFO填满数据
LIS2DH12_read_data(cal_data);
for (int i = 0; i < num_samples; i++) {
x_sum += cal_data[i].x;
y_sum += cal_data[i].y;
}
zero_g_offset.x = (float)x_sum / num_samples;
zero_g_offset.y = (float)y_sum / num_samples;
zero_g_offset.z = 0; // Z轴主要受重力影响不进行校准
xlog("校准完成. X轴偏移: %.2f, Y轴偏移: %.2f\n", zero_g_offset.x, zero_g_offset.y);
}
// 初始化并配置LIS2DH12传感器
u8 LIS2DH12_Config(void) {
if (LIS2DH12_Check() != 1) {
xlog("LIS2DH12 I2C检查失败\n");
return -1;
}
// 统一配置: 25Hz采样率, +/-8g量程, 普通模式(10位)
SL_MEMS_i2cWrite(LIS2DH12_W_ADDR, LIS2DH12_CTRL_REG1, 0x37); // 25 Hz ODR
SL_MEMS_i2cWrite(LIS2DH12_W_ADDR, LIS2DH12_CTRL_REG4, 0x20); // +/-8g, BDU enabled
SL_MEMS_i2cWrite(LIS2DH12_W_ADDR, LIS2DH12_CTRL_REG5, 0x40); // 使能FIFO
SL_MEMS_i2cWrite(LIS2DH12_W_ADDR, LIS2DH12_FIFO_CTRL_REG, 0x80); // 流模式
// 执行开机校准
LIS2DH12_calibrate();
xlog("LIS2DH12 I2C检查成功\n");
return 0;
}
// 判断传感器是否处于静止状态
2025-10-29 16:24:16 +08:00
bool is_sensor_stable(axis_info_t *accel_data, int sample_count) {
float mean_x = 0, mean_y = 0, mean_z = 0;
float variance_x = 0, variance_y = 0, variance_z = 0;
2025-10-30 11:33:38 +08:00
if (sample_count <= 1) return true;
// 1. 计算均值
2025-10-29 16:24:16 +08:00
for (int i = 0; i < sample_count; i++) {
mean_x += accel_data[i].x;
mean_y += accel_data[i].y;
mean_z += accel_data[i].z;
}
mean_x /= sample_count;
mean_y /= sample_count;
mean_z /= sample_count;
2025-10-30 11:33:38 +08:00
2025-10-29 16:24:16 +08:00
gsensor_xtell.x = mean_x;
gsensor_xtell.y = mean_y;
gsensor_xtell.z = mean_z;
2025-10-30 11:33:38 +08:00
// 2. 计算方差
2025-10-29 16:24:16 +08:00
for (int i = 0; i < sample_count; i++) {
variance_x += (accel_data[i].x - mean_x) * (accel_data[i].x - mean_x);
variance_y += (accel_data[i].y - mean_y) * (accel_data[i].y - mean_y);
variance_z += (accel_data[i].z - mean_z) * (accel_data[i].z - mean_z);
}
variance_x /= (sample_count - 1);
variance_y /= (sample_count - 1);
variance_z /= (sample_count - 1);
2025-10-30 11:33:38 +08:00
// 3. 如果方差大于阈值,则认为在运动
2025-10-29 16:24:16 +08:00
if (variance_x > THRESHOLD || variance_y > THRESHOLD || variance_z > THRESHOLD) {
return false;
}
2025-10-30 11:33:38 +08:00
return true;
2025-10-29 16:24:16 +08:00
}
2025-10-30 11:33:38 +08:00
// 获取当前的总加速度(包含重力),单位 m/s^2
2025-10-29 16:24:16 +08:00
axis_info_xtell get_current_accel_mss(void) {
axis_info_xtell accel_mss;
2025-10-30 11:33:38 +08:00
// 灵敏度 @ +/-8g 普通模式 (10-bit) = 12 mg/LSB
const float sensitivity_g_per_lsb = 0.012f;
// 在转换前,先减去校准测得的零点偏移
accel_mss.x = ((float)gsensor_xtell.x - zero_g_offset.x) * sensitivity_g_per_lsb * GRAVITY_EARTH;
accel_mss.y = ((float)gsensor_xtell.y - zero_g_offset.y) * sensitivity_g_per_lsb * GRAVITY_EARTH;
accel_mss.z = (float)gsensor_xtell.z * sensitivity_g_per_lsb * GRAVITY_EARTH;
2025-10-29 16:24:16 +08:00
return accel_mss;
}
2025-10-30 11:33:38 +08:00
// 获取计算好的运动数据(速度和距离)
2025-10-29 16:24:16 +08:00
void get_motion_data(motion_data_t *data) {
if (data) {
memcpy(data, &motion_data, sizeof(motion_data_t));
}
}
2025-10-30 11:33:38 +08:00
// 获取移除重力后的线性加速度
axis_info_xtell get_linear_accel_mss(void) {
return linear_accel_global;
}
2025-10-29 16:24:16 +08:00
2025-10-30 11:33:38 +08:00
// 核心计算任务,由定时器周期性调用
void xtell_i2c_test() {
// 1. 读取一批最新的传感器数据
2025-10-29 16:24:16 +08:00
LIS2DH12_read_data(current_data);
2025-10-30 11:33:38 +08:00
// 2. 判断传感器当前是否静止
2025-10-29 16:24:16 +08:00
sensor_is_stable = is_sensor_stable(current_data, SAMPLE_COUNT);
2025-10-30 11:33:38 +08:00
// 3. 获取校准和转换后的总加速度 (m/s^2)
2025-10-29 16:24:16 +08:00
axis_info_xtell current_accel_mss = get_current_accel_mss();
2025-10-30 11:33:38 +08:00
// 4. 使用低通滤波器估算重力向量
2025-10-29 16:24:16 +08:00
gravity_vector.x = LPF_ALPHA * gravity_vector.x + (1.0f - LPF_ALPHA) * current_accel_mss.x;
gravity_vector.y = LPF_ALPHA * gravity_vector.y + (1.0f - LPF_ALPHA) * current_accel_mss.y;
gravity_vector.z = LPF_ALPHA * gravity_vector.z + (1.0f - LPF_ALPHA) * current_accel_mss.z;
2025-10-30 11:33:38 +08:00
// 5. 从总加速度中减去重力,得到线性加速度
linear_accel_global.x = current_accel_mss.x - gravity_vector.x;
linear_accel_global.y = current_accel_mss.y - gravity_vector.y;
linear_accel_global.z = current_accel_mss.z - gravity_vector.z;
2025-10-29 16:24:16 +08:00
2025-10-30 11:33:38 +08:00
// 6. 应用死区:忽略过小的加速度值(噪声)
if (fabsf(linear_accel_global.x) < DEADZONE_MSS) linear_accel_global.x = 0.0f;
if (fabsf(linear_accel_global.y) < DEADZONE_MSS) linear_accel_global.y = 0.0f;
if (fabsf(linear_accel_global.z) < DEADZONE_MSS) linear_accel_global.z = 0.0f;
2025-10-29 16:24:16 +08:00
2025-10-30 11:33:38 +08:00
// 7. 积分线性加速度,得到速度
motion_data.velocity.x += linear_accel_global.x * SAMPLING_PERIOD_S;
motion_data.velocity.y += linear_accel_global.y * SAMPLING_PERIOD_S;
motion_data.velocity.z += linear_accel_global.z * SAMPLING_PERIOD_S;
// 8. 如果传感器静止,重置速度和距离以消除漂移
2025-10-29 16:24:16 +08:00
if (sensor_is_stable) {
motion_data.velocity.x = 0.0f;
motion_data.velocity.y = 0.0f;
motion_data.velocity.z = 0.0f;
2025-10-30 11:33:38 +08:00
motion_data.distance.x = 0.0f;
motion_data.distance.y = 0.0f;
motion_data.distance.z = 0.0f;
2025-10-29 16:24:16 +08:00
}
2025-10-30 11:33:38 +08:00
// 9. 积分速度,得到距离
2025-10-29 16:24:16 +08:00
motion_data.distance.x += motion_data.velocity.x * SAMPLING_PERIOD_S;
motion_data.distance.y += motion_data.velocity.y * SAMPLING_PERIOD_S;
motion_data.distance.z += motion_data.velocity.z * SAMPLING_PERIOD_S;
2025-10-30 11:33:38 +08:00
// 10. 计算并打印总的移动距离(可选,用于调试)
2025-10-29 16:24:16 +08:00
float total_distance_magnitude = sqrtf(motion_data.distance.x * motion_data.distance.x +
motion_data.distance.y * motion_data.distance.y +
motion_data.distance.z * motion_data.distance.z);
2025-10-30 11:33:38 +08:00
// xlog("Total distance traveled: %.2f m\n", total_distance_magnitude);
2025-10-29 16:24:16 +08:00
}