用STM32CubeMX和ADXL345做个简易计步器:从I2C配置到角度计算全流程
2026/5/12 16:03:08 网站建设 项目流程

用STM32CubeMX和ADXL345打造高精度计步器:从硬件配置到算法优化实战

在智能穿戴设备普及的今天,计步功能已成为健康监测的基础需求。本文将带您从零开始,使用STM32微控制器和ADXL345三轴加速度传感器,构建一个具备实用价值的计步器系统。不同于简单的传感器驱动教程,我们将重点关注实际应用场景中的数据处理技巧运动特征识别算法,让您的项目真正具备产品级精度。

1. 硬件系统搭建与CubeMX配置

ADXL345是一款低功耗、高分辨率的三轴加速度传感器,特别适合穿戴式设备的运动监测。其I2C接口与STM32的连接仅需四条线:

  • SCL:时钟线(PB6)
  • SDA:数据线(PB7)
  • VCC:3.3V电源
  • GND:共地连接

在STM32CubeMX中的配置步骤如下:

  1. 创建新工程并选择您的STM32型号
  2. 启用I2C1外设(标准模式,100kHz)
  3. 配置PB6和PB7引脚为I2C功能
  4. 生成代码前确保开启I2C中断(可选)
// CubeMX生成的I2C初始化代码片段 hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); }

提示:ADXL345的I2C地址默认为0x53(7位地址),若A0引脚接高电平则为0x1D

2. ADXL345传感器驱动开发

传感器初始化需要配置几个关键寄存器:

寄存器地址配置值功能说明
0x2D0x08退出待机模式
0x310x0B±16g量程,13位分辨率
0x2C0x0F100Hz输出数据速率

完整的初始化函数示例:

#define ADXL345_ADDR 0x53 void ADXL345_Init(void) { uint8_t data[2]; // 退出待机模式 data[0] = 0x2D; // POWER_CTL寄存器 data[1] = 0x08; // 测量模式 HAL_I2C_Master_Transmit(&hi2c1, ADXL345_ADDR<<1, data, 2, 100); // 设置数据格式 data[0] = 0x31; data[1] = 0x0B; // 全分辨率,右对齐,±16g HAL_I2C_Master_Transmit(&hi2c1, ADXL345_ADDR<<1, data, 2, 100); // 设置输出数据速率 data[0] = 0x2C; data[1] = 0x0F; // 100Hz HAL_I2C_Master_Transmit(&hi2c1, ADXL345_ADDR<<1, data, 2, 100); }

读取三轴加速度数据的函数实现:

void ADXL345_ReadAccel(int16_t *x, int16_t *y, int16_t *z) { uint8_t data[6]; uint8_t reg = 0x32; // DATAX0寄存器地址 HAL_I2C_Mem_Read(&hi2c1, ADXL345_ADDR<<1, reg, I2C_MEMADD_SIZE_8BIT, data, 6, 100); *x = (int16_t)((data[1] << 8) | data[0]); *y = (int16_t)((data[3] << 8) | data[2]); *z = (int16_t)((data[5] << 8) | data[4]); }

3. 计步算法设计与实现

原始加速度数据需要经过多个处理阶段才能准确识别步伐:

  1. 数据预处理

    • 去除重力分量(静态偏移)
    • 三轴数据合成矢量幅度
    float accel_magnitude(int16_t x, int16_t y, int16_t z) { // ADXL345的灵敏度为3.9mg/LSB(±16g量程) float fx = x * 0.0039; float fy = y * 0.0039; float fz = z * 0.0039; return sqrt(fx*fx + fy*fy + fz*fz); }
  2. 低通滤波(消除高频噪声):

    #define ALPHA 0.2 // 滤波系数 float low_pass_filter(float new_value, float old_value) { return ALPHA * new_value + (1 - ALPHA) * old_value; }
  3. 峰值检测算法

    • 设置动态阈值
    • 检测波峰波谷模式
    • 时间窗口验证(防止误判)

完整的计步状态机实现:

typedef struct { float threshold_high; float threshold_low; uint8_t step_count; uint32_t last_step_time; uint8_t state; // 0=等待上升,1=等待下降 } StepDetector; void process_accel_data(StepDetector *detector, float accel_mag) { static float filtered = 0; filtered = low_pass_filter(accel_mag, filtered); switch(detector->state) { case 0: // 等待超过高阈值 if(filtered > detector->threshold_high) { detector->state = 1; detector->threshold_low = filtered * 0.7; // 动态调整低阈值 } break; case 1: // 等待低于低阈值 if(filtered < detector->threshold_low) { uint32_t now = HAL_GetTick(); if(now - detector->last_step_time > 200) { // 最小步频500ms detector->step_count++; detector->last_step_time = now; } detector->state = 0; detector->threshold_high = filtered * 1.3; // 动态调整高阈值 } break; } }

4. 系统优化与性能提升

提高计步精度的实用技巧:

  • 动态阈值调整:根据用户运动强度自动调整触发阈值

  • 运动状态检测:区分步行、跑步和静止状态

  • 卡尔曼滤波:更高级的噪声处理方法

    typedef struct { float q; // 过程噪声协方差 float r; // 测量噪声协方差 float x; // 估计值 float p; // 估计误差协方差 float k; // 卡尔曼增益 } KalmanFilter; float kalman_update(KalmanFilter *kf, float measurement) { // 预测更新 kf->p = kf->p + kf->q; // 测量更新 kf->k = kf->p / (kf->p + kf->r); kf->x = kf->x + kf->k * (measurement - kf->x); kf->p = (1 - kf->k) * kf->p; return kf->x; }
  • 计步结果验证:通过串口输出原始数据和步数统计,方便调试

    void debug_output(int16_t x, int16_t y, int16_t z, uint32_t steps) { printf("X:%6d Y:%6d Z:%6d Steps:%lu\r\n", x, y, z, steps); }

5. 用户界面与功能扩展

将计步结果显示在TFT LCD上的实现要点:

  1. 显示初始化

    void LCD_Init(void) { // 初始化SPI接口 // 设置显示方向 // 清屏并设置默认字体 }
  2. 计步数据显示

    void display_step_count(uint32_t steps) { char buf[20]; sprintf(buf, "Steps: %lu", steps); LCD_DrawString(10, 50, buf, BLACK, WHITE); }
  3. 历史数据记录(需外接EEPROM或FRAM):

    #define EEPROM_ADDR 0xA0 void save_daily_steps(uint32_t steps) { uint8_t data[4]; data[0] = (steps >> 24) & 0xFF; data[1] = (steps >> 16) & 0xFF; data[2] = (steps >> 8) & 0xFF; data[3] = steps & 0xFF; HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR, 0x00, I2C_MEMADD_SIZE_8BIT, data, 4, 100); }
  4. 添加功能按键

    • 复位计步器
    • 查看历史数据
    • 切换显示模式

在实际项目中,我发现ADXL345的放置位置对计步精度影响很大。最佳位置是靠近身体质心的腰部,如果放在口袋或手腕,可能需要针对性的算法调整。另外,早晨刚佩戴时的10-20步常常是穿脱动作导致的误判,可以通过增加启动延迟来避免。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询