Files
2026-02-05 13:22:38 +08:00

210 lines
6.2 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* ==================================================
* @file imu_lis3dhtr.c
* @brief TODO 描述该文件的功能
* @author wangb
* @date 2026-01-27 12:21
* @version 1.0
*
* @details 本文件包含...
*
* @copyright Copyright (c) 2026 wangb. All Rights Reserved.
*
* @license 不开源
* ==================================================
*/
#include "mems_lis3dhtr.h"
#include "cmsis_os2.h"
#include "elog.h"
#include "i2c.h"
volatile uint8_t lis3dh_int_flag = 0;
static uint8_t last_int_src = 0; // 记录上一次中断源
/* ================= 内部 I2C 读写 ================= */
void lis3dh_read(uint8_t reg, uint8_t *data, uint16_t len)
{
/* 多字节读必须置位 bit7 */
if (len > 1)
reg |= 0x80;
HAL_I2C_Mem_Read(&hi2c1,
LIS3DHTR_I2C_ADDR,
reg,
I2C_MEMADD_SIZE_8BIT,
data,
len,
1000);
}
void lis3dh_write(uint8_t reg, uint8_t data)
{
HAL_I2C_Mem_Write(&hi2c1,
LIS3DHTR_I2C_ADDR,
reg,
I2C_MEMADD_SIZE_8BIT,
&data,
1,
1000);
}
/* ================= 清除所有中断标志 ================= */
void lis3dh_clear_all_int_flags(void) {
uint8_t dummy;
// 读取INT1_SRC清除中断锁存关键
lis3dh_read(LIS3DH_REG_INT1_SRC, &dummy, 1);
// 读取状态寄存器确保数据就绪标志清除
lis3dh_read(LIS3DH_REG_STATUS, &dummy, 1);
// 读取REFERENCE寄存器重置高通滤波器
lis3dh_read(LIS3DH_REG_REFERENCE, &dummy, 1);
last_int_src = 0;
}
/* ================= LIS3DH 中断初始化 ================= */
static void lis3dh_int1_fall_init(void) {
uint8_t val;
/* 第一步:禁用所有中断并清除标志 */
lis3dh_write(LIS3DH_REG_CTRL3, 0x00);
lis3dh_write(LIS3DH_REG_INT1_CFG, 0x00);
osDelay(10);
/* 第二步:清除所有可能的中断标志 */
lis3dh_clear_all_int_flags();
osDelay(10);
/* 第三步配置CTRL2 - 高通滤波器 */
// 0x11 = 100Hz截止频率HP使能
lis3dh_write(LIS3DH_REG_CTRL2, 0x11);
/* 第四步配置CTRL3 - INT1引脚输出AOI1中断 */
val = 0x40; // I1_AOI1 = 1
lis3dh_write(LIS3DH_REG_CTRL3, val);
/* 第五步INT1_CFG - 配置检测逻辑 */
// 0x2A = 0010 1010只检测Z轴高阈值和低阈值
// 0x3F = 0011 1111检测所有轴根据你的日志0x25/0x65包含多个轴
val = 0x2A; // 先用Z轴测试
lis3dh_write(LIS3DH_REG_INT1_CFG, val);
/* 第六步INT1_THS - 阈值设置 */
val = 15; // 15 * 16mg = 240mg ≈ 0.24g(自由落体阈值)
lis3dh_write(LIS3DH_REG_INT1_THS, val);
/* 第七步INT1_DUR - 持续时间(去抖动) */
val = 2; // 2 * 1/ODR = 20ms @ 100Hz
lis3dh_write(LIS3DH_REG_INT1_DUR, val);
/* 第八步配置CTRL5 - 锁存中断 */
// 0x0A = 0000 1010LIR_INT1=1锁存INT1高阈值使能
lis3dh_write(LIS3DH_REG_CTRL5, 0x0A);
/* 第九步:再次清除所有标志 */
lis3dh_clear_all_int_flags();
elog_info("MEMS", "INT1 fall detect configured (Latch Mode)");
}
/* ================= LIS3DH 初始化 ================= */
uint8_t imu_lis3dhtr_init(void) {
uint8_t whoami = 0;
lis3dh_read(LIS3DH_REG_WHOAMI, &whoami, 1);
elog_info("MEMS", "LIS3DHTR WHO_AM_I = 0x%02X", whoami);
if (whoami != 0x33)
return 0;
/* CTRL_REG1: 100Hz ODR, XYZ 使能 */
lis3dh_write(LIS3DH_REG_CTRL1, 0x57);
/* CTRL_REG4: BDU=1, HR=1, FS=±2g */
lis3dh_write(LIS3DH_REG_CTRL4, 0xA0);
/* 初始化 INT1 跌落检测 */
lis3dh_int1_fall_init();
/* 读回验证 */
uint8_t c1, c2, c3, c4, c5, cfg;
lis3dh_read(LIS3DH_REG_CTRL1, &c1, 1);
lis3dh_read(LIS3DH_REG_CTRL2, &c2, 1);
lis3dh_read(LIS3DH_REG_CTRL3, &c3, 1);
lis3dh_read(LIS3DH_REG_CTRL4, &c4, 1);
lis3dh_read(LIS3DH_REG_CTRL5, &c5, 1);
lis3dh_read(LIS3DH_REG_INT1_CFG, &cfg, 1);
elog_info("MEMS", "CTRL1=0x%02X CTRL2=0x%02X CTRL3=0x%02X", c1, c2, c3);
elog_info("MEMS", "CTRL4=0x%02X CTRL5=0x%02X INT1_CFG=0x%02X", c4, c5, cfg);
return 1;
}
/* ================= 读取加速度 ================= */
uint8_t imu_lis3dhtr_read_accel(lis3dh_accel_t *accel)
{
uint8_t status;
lis3dh_read(LIS3DH_REG_STATUS, &status, 1);
if ((status & 0x08) == 0)
return 0; // 新数据未准备好
uint8_t buf[6];
lis3dh_read(LIS3DH_REG_OUT_X_L, buf, 6);
int16_t raw_x = ((int16_t)buf[1] << 8 | buf[0]) >> 4;
int16_t raw_y = ((int16_t)buf[3] << 8 | buf[2]) >> 4;
int16_t raw_z = ((int16_t)buf[5] << 8 | buf[4]) >> 4;
accel->x_g = raw_x * 0.001f; // ±2g HR模式1LSB≈1mg
accel->y_g = raw_y * 0.001f;
accel->z_g = raw_z * 0.001f;
return 1;
}
/* ================= 外部中断回调 ================= */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if (GPIO_Pin == lis3dhtr_Pin) {
uint8_t src;
// 1. 读取中断源(这会清除锁存中断)
lis3dh_read(LIS3DH_REG_INT1_SRC, &src, 1);
// 2. 有效性检查:源寄存器必须有中断标志
if (src == 0x00) {
// 可能是假中断,额外操作确保清除
uint8_t dummy;
lis3dh_read(LIS3DH_REG_INT1_SRC, &dummy, 1);
return;
}
// 3. 去重:避免相同中断源连续触发
if (src == last_int_src) {
// 相同中断,可能是未及时处理,强制清除
elog_debug("MEMS", "Duplicate INT1 SRC = 0x%02X", src);
return;
}
// 4. 记录并处理
last_int_src = src;
elog_warn("MEMS", "INT1 SRC = 0x%02X", src);
// 5. 解析中断类型(用于调试和高级处理)
if (src & 0x40) elog_debug("MEMS", "Z high triggered");
if (src & 0x20) elog_debug("MEMS", "Z low triggered");
if (src & 0x10) elog_debug("MEMS", "Y high triggered");
if (src & 0x08) elog_debug("MEMS", "Y low triggered");
if (src & 0x04) elog_debug("MEMS", "X high triggered");
if (src & 0x02) elog_debug("MEMS", "X low triggered");
// 6. 设置处理标志
lis3dh_int_flag = 1;
}
}