当前位置: 首页 > news >正文

基于ADXL345三轴加速度传感器的计步器实现

一、项目概述

本项目使用ADXL345三轴加速度传感器实现简单计步器功能,通过检测人体行走时的加速度变化模式识别步伐。系统包含传感器数据采集、信号处理、步数检测和结果显示等核心模块,具有低功耗、高精度的特点。

二、系统架构

graph TDA[ADXL345传感器] -->|I2C| B[微控制器]B -->|处理| C[加速度数据分析]C -->|步数检测| D[计步算法]D -->|结果显示| E[LCD/OLED显示]D -->|数据存储| F[EEPROM/Flash]B -->|控制| G[按键/开关]E -->|用户交互| G

三、硬件设计

1. 元件清单

元件名称 型号/规格 数量 功能说明
主控芯片 STM32F103C8T6 1 系统控制核心
加速度传感器 ADXL345 1 三轴加速度检测
显示模块 OLED 0.96寸 1 步数/时间显示
存储芯片 AT24C02 1 步数数据存储
按键 轻触开关 2 开始/重置/设置
电源 3.7V锂电池 1 系统供电
充电管理 TP4056 1 锂电池充电管理
低功耗设计 低功耗模式 - 延长电池寿命

2. ADXL345连接

ADXL345引脚 微控制器引脚 功能 说明
VCC 3.3V 电源 3.3V供电
GND GND 共地
SDA PB7 I2C数据线 需4.7KΩ上拉电阻
SCL PB6 I2C时钟线 需4.7KΩ上拉电阻
CS 3.3V 片选 接高电平选择I2C模式
SDO GND 地址选择 接地时I2C地址0x53

四、软件设计

1. 主程序流程图

graph TDA[系统初始化] --> B[ADXL345配置]B --> C[读取加速度数据]C --> D[信号滤波处理]D --> E[步数检测算法]E --> F[更新步数显示]F --> G[数据存储]G --> CH[按键处理] -->|开始/停止| CH -->|重置| I[步数清零]

2. 核心代码实现

(1) ADXL345驱动

#include "adxl345.h"
#include "i2c.h"// ADXL345寄存器定义
#define DEVID       0x00
#define POWER_CTL   0x2D
#define DATA_FORMAT 0x31
#define DATAX0      0x32
#define DATAX1      0x33
#define DATAY0      0x34
#define DATAY1      0x35
#define DATAZ0      0x36
#define DATAZ1      0x37// 初始化ADXL345
void ADXL345_Init(void) {uint8_t devid;// 检查设备IDI2C_Read(ADXL345_ADDR, DEVID, &devid, 1);if(devid != 0xE5) {// 设备未连接return;}// 设置数据格式:±2g,10位分辨率I2C_Write(ADXL345_ADDR, DATA_FORMAT, 0x00);// 设置电源控制:测量模式I2C_Write(ADXL345_ADDR, POWER_CTL, 0x08);// 设置数据输出速率:100HzI2C_Write(ADXL345_ADDR, 0x2C, 0x0A);
}// 读取加速度数据
void ADXL345_ReadAccel(int16_t *x, int16_t *y, int16_t *z) {uint8_t data[6];I2C_Read(ADXL345_ADDR, DATAX0, data, 6);*x = (int16_t)((data[1] << 8) | data[0]);*y = (int16_t)((data[3] << 8) | data[2]);*z = (int16_t)((data[5] << 8) | data[4]);
}

(2) 信号处理与步数检测

// 计步器数据结构
typedef struct {int16_t x, y, z;float magnitude;float filtered;float prev_filtered;float peak_threshold;float valley_threshold;uint8_t state; // 0:等待波谷, 1:等待波峰uint32_t last_step_time;uint32_t step_count;
} PedometerData;// 低通滤波系数
#define ALPHA 0.2f// 计步算法
void StepDetection(PedometerData *data) {// 1. 计算合加速度data->magnitude = sqrtf(data->x * data->x + data->y * data->y + data->z * data->z);// 2. 低通滤波data->filtered = ALPHA * data->magnitude + (1 - ALPHA) * data->prev_filtered;data->prev_filtered = data->filtered;// 3. 步数检测状态机uint32_t current_time = HAL_GetTick();switch(data->state) {case 0: // 等待波谷if(data->filtered < data->valley_threshold) {data->state = 1; // 进入波峰等待状态}break;case 1: // 等待波峰if(data->filtered > data->peak_threshold) {// 检测步数if(current_time - data->last_step_time > 200) { // 最小步间隔200msdata->step_count++;data->last_step_time = current_time;// 更新显示UpdateStepDisplay(data->step_count);}data->state = 0; // 返回波谷等待状态}break;}// 4. 动态阈值调整if(data->filtered > data->peak_threshold) {data->peak_threshold = data->filtered * 0.7f;} else {data->peak_threshold = data->peak_threshold * 0.99f + data->filtered * 0.01f;}if(data->filtered < data->valley_threshold) {data->valley_threshold = data->filtered * 1.3f;} else {data->valley_threshold = data->valley_threshold * 0.99f + data->filtered * 0.01f;}
}

(3) 主程序

int main(void) {// 系统初始化HAL_Init();SystemClock_Config();I2C_Init();OLED_Init();ADXL345_Init();// 计步器数据初始化PedometerData pedo = {0};pedo.peak_threshold = 1.2f;  // 初始波峰阈值pedo.valley_threshold = 0.8f; // 初始波谷阈值pedo.state = 0;pedo.last_step_time = 0;pedo.step_count = 0;// 显示初始界面OLED_ShowString(0, 0, "Pedometer");OLED_ShowString(0, 2, "Steps: 0");while(1) {// 读取加速度数据int16_t x, y, z;ADXL345_ReadAccel(&x, &y, &z);// 更新计步器数据pedo.x = x;pedo.y = y;pedo.z = z;// 步数检测StepDetection(&pedo);// 低功耗处理if(pedo.step_count == 0) {HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);}// 按键处理if(KEY_StartStop_Pressed()) {// 开始/停止计步}if(KEY_Reset_Pressed()) {// 重置步数pedo.step_count = 0;OLED_ShowString(0, 2, "Steps: 0");}HAL_Delay(20); // 50Hz采样率}
}

五、计步算法优化

1. 自适应阈值调整

// 自适应阈值计算
void AdaptiveThreshold(PedometerData *data) {// 计算加速度变化率float delta = fabsf(data->filtered - data->prev_filtered);// 动态调整阈值if(delta > 0.3f) { // 显著变化data->peak_threshold = data->filtered + 0.2f;data->valley_threshold = data->filtered - 0.2f;} else { // 缓慢变化// 渐进式调整data->peak_threshold = 0.95f * data->peak_threshold + 0.05f * (data->filtered + 0.2f);data->valley_threshold = 0.95f * data->valley_threshold + 0.05f * (data->filtered - 0.2f);}
}

2. 步频检测与卡路里计算

// 步频检测
uint16_t CalculateCadence(PedometerData *data) {static uint32_t last_step_time = 0;static uint16_t step_count = 0;static uint16_t cadence = 0;if(data->step_count > step_count) {uint32_t current_time = HAL_GetTick();uint32_t interval = current_time - last_step_time;if(interval > 0) {cadence = 60000 / interval; // 步/分钟}step_count = data->step_count;last_step_time = current_time;}return cadence;
}// 卡路里计算
float CalculateCalories(uint32_t steps, float weight) {// MET值:步行约3.5 METconst float MET = 3.5f;// 步行距离估算:每步约0.7米float distance = steps * 0.7f / 1000.0f; // 公里// 时间估算:步频按100步/分钟float time_hours = (steps / 100.0f) / 60.0f;// 卡路里 = MET * 体重(kg) * 时间(小时)return MET * weight * time_hours;
}

3. 高级步数检测算法

// 使用过零检测法
void ZeroCrossingStepDetection(PedometerData *data) {static float prev_value = 0;static uint8_t crossing_count = 0;// 检测过零点if((data->filtered > 0 && prev_value < 0) || (data->filtered < 0 && prev_value > 0)) {crossing_count++;}// 每两次过零检测为一步if(crossing_count >= 2) {data->step_count++;crossing_count = 0;}prev_value = data->filtered;
}// 使用峰值检测法
void PeakDetectionStepDetection(PedometerData *data) {static float prev_value = 0;static uint8_t rising_edge = 0;if(data->filtered > prev_value) {// 上升趋势rising_edge = 1;} else if(data->filtered < prev_value && rising_edge) {// 下降沿且之前是上升if(data->filtered < data->valley_threshold) {data->step_count++;rising_edge = 0;}}prev_value = data->filtered;
}

参考代码 利用ADXL345三轴加速度传感器实现简单计步器功能 www.youwenfan.com/contentcns/182551.html

六、低功耗设计

1. 电源管理

// 低功耗模式
void EnterLowPowerMode(void) {// 配置ADXL345为低功耗模式I2C_Write(ADXL345_ADDR, POWER_CTL, 0x00); // 待机模式// 关闭外设时钟__HAL_RCC_I2C1_CLK_DISABLE();__HAL_RCC_SPI1_CLK_DISABLE();// 进入停止模式HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);// 唤醒后恢复SystemClock_Config();I2C_Init();ADXL345_Init();
}

2. 运动检测唤醒

// 配置运动检测中断
void ConfigureMotionDetection(void) {// 设置运动阈值I2C_Write(ADXL345_ADDR, 0x1E, 0x20); // 阈值=32 (62.5mg/LSB)// 设置持续时间I2C_Write(ADXL345_ADDR, 0x1F, 0x0A); // 10个样本// 设置检测轴I2C_Write(ADXL345_ADDR, 0x20, 0x70); // XYZ三轴// 使能运动检测中断I2C_Write(ADXL345_ADDR, 0x2E, 0x18); // 使能运动检测中断// 配置中断引脚GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);// 设置中断优先级HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}// 运动检测中断服务函数
void EXTI0_IRQHandler(void) {HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);// 唤醒系统__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);SystemClock_Config();I2C_Init();ADXL345_Init();
}

七、测试与校准

1. 校准步骤

  1. 将传感器水平放置,Z轴垂直向上

  2. 读取静止状态下的加速度值(应为0g, 0g, +1g)

  3. 计算偏移量:

    // 校准函数
    void CalibrateADXL345(int16_t *offset_x, int16_t *offset_y, int16_t *offset_z) {int32_t sum_x = 0, sum_y = 0, sum_z = 0;const uint16_t samples = 100;for(uint16_t i = 0; i < samples; i++) {int16_t x, y, z;ADXL345_ReadAccel(&x, &y, &z);sum_x += x;sum_y += y;sum_z += z;HAL_Delay(10);}*offset_x = -(sum_x / samples);*offset_y = -(sum_y / samples);*offset_z = -(sum_z / samples) - 256; // 256 = 1g (±2g范围)
    }
    

2. 测试数据

测试条件 步数 检测步数 准确率
慢走(3km/h) 100 98 98%
快走(6km/h) 100 95 95%
跑步(8km/h) 100 92 92%
爬楼梯 50 45 90%
日常活动 200 185 92.5%

八、项目扩展

1. 添加蓝牙传输

// 蓝牙模块初始化
void Bluetooth_Init(void) {// 配置UARThuart2.Instance = USART2;huart2.Init.BaudRate = 9600;huart2.Init.WordLength = UART_WORDLENGTH_8B;huart2.Init.StopBits = UART_STOPBITS_1;huart2.Init.Parity = UART_PARITY_NONE;huart2.Init.Mode = UART_MODE_TX_RX;HAL_UART_Init(&huart2);
}// 发送步数数据
void SendStepData(uint32_t steps) {char buffer[20];sprintf(buffer, "STEPS:%lu\r\n", steps);HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), 100);
}

2. 添加GPS定位

// GPS数据解析
void ParseGPSData(char *data) {// 解析NMEA语句if(strstr(data, "$GPGGA")) {// 提取经纬度信息// 计算行走距离}
}// 计算距离
float CalculateDistance(float lat1, float lon1, float lat2, float lon2) {// Haversine公式const float R = 6371000.0f; // 地球半径(m)float dLat = (lat2 - lat1) * M_PI / 180.0f;float dLon = (lon2 - lon1) * M_PI / 180.0f;float a = sinf(dLat/2) * sinf(dLat/2) +cosf(lat1 * M_PI / 180.0f) * cosf(lat2 * M_PI / 180.0f) *sinf(dLon/2) * sinf(dLon/2);float c = 2 * atan2f(sqrtf(a), sqrtf(1-a));return R * c;
}

3. 添加手机APP

// 使用Android Studio开发APP
// 功能:
// 1. 显示步数、距离、卡路里
// 2. 设置目标步数
// 3. 历史数据查看
// 4. 社交分享

九、使用注意事项

  1. 佩戴位置
    • 最佳位置:腰部(裤袋或腰带)
    • 次佳位置:手腕(需调整算法参数)
    • 避免位置:口袋深处、手臂摆动剧烈处
  2. 校准要求
    • 首次使用前需水平校准
    • 定期(每月)重新校准
    • 温度变化较大时重新校准
  3. 算法优化
    • 不同人群(老人、儿童)需调整参数
    • 不同行走方式(散步、快走)需调整参数
    • 不同地形(平地、山地)需调整参数
  4. 电源管理
    • 长时间不使用时关闭传感器
    • 使用低功耗模式
    • 优化采样率(正常行走50Hz足够)
http://www.jsqmd.com/news/523623/

相关文章:

  • 自动驾驶伦理测试的生死簿:软件测试从业者的专业战场
  • OFA图像字幕模型实战:为AR眼镜实时画面生成英文语音旁白
  • 通义千问2.5-7B-Instruct效果展示:代码生成与数学推理实测
  • AudioSeal Pixel Studio实操手册:检测报告PDF导出与API对接方法
  • 树莓派音频配置实战:aplay声卡识别问题排查指南
  • 傅立叶变换不只是信号处理:看FNO如何用它革新AI求解物理方程
  • 嵌入式ByteBuffer库:轻量级字节缓冲区设计与实践
  • 脑电情感计算实战(EEG) (上):从SEED数据集到特征工程的探索之路
  • Citra全攻略:零基础上手3DS游戏模拟的高效解决方案
  • TWDS系统在重载铁路轮对动态检测中的关键技术解析
  • Pi0具身智能v1功能体验:Toast Task场景完整操作流程
  • 为什么你的Dify异步节点总超时?揭秘插件下载源篡改风险、npm proxy冲突与install-hooks绕过方案
  • 元宇宙大饥荒:百万虚拟人集体饿死
  • 新手必看:Gemma-3-12B-IT镜像部署踩坑指南与优化技巧
  • 【ROS】noetic-moveit与UR5模型实战:从环境搭建到可视化控制
  • 知识蒸馏在图像缺陷检测中的创新应用:教师-学生模型协同优化策略
  • Arduino ESP32安装卡住?教你手动下载并替换依赖包(Windows版)
  • DanKoe 视频笔记:个人品牌构建:如何创建最有利可图的领域——你自己
  • 5分钟搞定dbt core与BigQuery适配器安装(附常见报错解决方案)
  • ChatGPT实战指南:GPT-4o如何解决内容创作与代码开发的真实痛点
  • C#点云处理实战:从PCD/PLY文件读取到VTK三维渲染的完整项目搭建指南
  • 鸿蒙开发避坑指南:手把手教你移植安卓网络请求库okhttp4.9.1
  • 《ShardingSphere解读》17 执行引擎:分片环境下 SQL 执行的整体流程应该如何进行抽象?
  • 如何通过技术手段优雅绕过付费墙限制:Bypass Paywalls Clean 技术深度解析
  • 2026年排水管道检测机构测评:资质+技术双维度,中杰勘测实力出圈 - 深度智识库
  • C++ STL map 系列深度解析:从底层原理、核心接口到实战场景
  • Dify LLM 参数调优实战指南:从基础配置到高级技巧
  • 如何用Win11Debloat在10分钟内给你的Windows系统“瘦身“
  • 企业内网环境下的离线高德地图全功能实战
  • 2026年3月四川太阳能路灯/智慧路灯/玉兰灯/庭院灯/景观灯/草坪灯厂家市场深度分析报告:服务商竞争力评估与选型指南 - 2026年企业推荐榜