STM32智能手表:基于FreeRTOS

发布于:2025-05-09 ⋅ 阅读:(23) ⋅ 点赞:(0)

引言

随着物联网和可穿戴设备的快速发展,智能手表作为典型代表,集成了传感器数据采集、实时显示、无线通信等多项功能。本文将深入剖析一个基于STM32和FreeRTOS的智能手表项目,从硬件架构到软件设计,逐步讲解如何构建一个完整的嵌入式系统。读者将学习到多任务管理、外设驱动开发、RTOS应用等核心知识。


一、项目概述

1.1 功能概览

本项目实现了一款具备以下功能的智能手表:

  • 环境监测:温湿度(DHT11)、运动姿态(MPU6050)
  • 健康监测:血氧饱和度(MAX30102)、心率(算法处理)
  • 人机交互:OLED显示、按键控制、蜂鸣器提示
  • 系统功能:RTC实时时钟、独立看门狗、低功耗管理
  • 无线通信:蓝牙数据传输(BLE模块)
  • 操作系统:FreeRTOS实现多任务调度
1.2 硬件架构
  • 主控芯片:STM32F407ZGT6(Cortex-M4, 168MHz)

传感器模块

  • MAX30102(血氧/心率)

  • MPU6050(加速度计+陀螺仪)

  • DHT11(温湿度)

  • 显示模块:0.96寸OLED(I2C接口)

  • 外围设备:LED指示灯、蜂鸣器、按键矩阵

  • 通信模块:HC-05蓝牙模块(USART)

1.3 软件架构

c

Copy

/* 文档1中的任务列表 */
static TaskHandle_t app_task_init_handle;        // 初始化任务
static TaskHandle_t app_task_mpu6050_handle;    // 运动检测
static TaskHandle_t app_task_key_handle;         // 按键处理
static TaskHandle_t app_task_dht_handle;         // 温湿度采集
static TaskHandle_t app_task_usart_handle;       // 串口通信
static TaskHandle_t app_task_rtc_handle;         // 实时时钟
static TaskHandle_t app_task_oled_handle;       // 显示刷新
static TaskHandle_t app_heart_task_handle;      // 心率血氧计算

二、FreeRTOS系统配置

2.1 内核基础配置

FreeRTOSConfig.h中设置关键参数:

c

Copy

#define configUSE_PREEMPTION        1   // 使用抢占式调度
#define configUSE_IDLE_HOOK         1   // 启用空闲任务钩子(低功耗)
#define configUSE_TICK_HOOK         0   
#define configCPU_CLOCK_HZ        168000000 // CPU频率
#define configTICK_RATE_HZ         1000     // 系统节拍1kHz
#define configMAX_PRIORITIES       15      // 优先级数量
#define configMINIMAL_STACK_SIZE   128     // 最小任务栈
#define configTOTAL_HEAP_SIZE      (30 * 1024) // 堆空间30KB
2.2 任务创建示例

c

Copy

void MX_FREERTOS_Init(void) {
  xTaskCreate(app_task_init, "Init", 256, NULL, 5, &app_task_init_handle);
  xTaskCreate(app_task_oled, "OLED", 512, NULL, 3, &app_task_oled_handle);
  // ...其他任务创建
}
2.3 关键机制
  • 互斥锁:保护共享资源(如printf、OLED操作)
  • 消息队列:传感器数据传递(LED控制指令队列示例)

c

Copy

QueueHandle_t xLEDQueue = xQueueCreate(10, sizeof(uint8_t));
  • 事件标志组:跨任务事件通知
  • 软件定时器:看门狗喂狗、周期性任务

三、硬件驱动详解

3.1 OLED显示模块(I2C)

驱动要点

  • 使用硬件I2C或模拟I2C(文档6)
  • 显存管理:128x64像素对应8页缓存
  • 中文显示:字模提取(文档8)

初始化流程

c

Copy

void OLED_Init(void) {
  I2C_Start();
  Write_IIC_Command(0xAE); // 关闭显示
  Write_IIC_Command(0xD5); // 设置时钟分频
  // ...更多初始化命令
}
3.2 MAX30102血氧传感器

数据采集关键代码(文档17):

c

Copy

void maxim_max30102_read_fifo(uint32_t *pun_red, uint32_t *pun_ir) {
  I2C_Start();
  I2C_WriteByte(MAX30102_WR_ADDR); 
  I2C_WriteByte(REG_FIFO_DATA); 
  I2C_Start();
  I2C_WriteByte(MAX30102_RD_ADDR);
  *pun_red = I2C_ReadByte() << 16;
  // ...连续读取6字节组成32位数据
}

数据处理算法(文档11):

c

Copy

void maxim_heart_rate_and_oxygen_saturation(
  uint32_t *ir_buffer, int32_t ir_length,
  uint32_t *red_buffer, int32_t *spo2, int8_t *valid_spo2,
  int32_t *heart_rate, int8_t *valid_hr) 
{
  // 信号滤波、峰值检测、SPO2查表计算
}
3.3 MPU6050运动检测

数据读取(文档9):

c

Copy

void MPU6050_ReadData(int16_t *accel, int16_t *gyro) {
  I2C_ReadBytes(MPU6050_ADDR, ACCEL_XOUT_H, (uint8_t*)buffer, 14);
  accel[0] = (buffer[0]<<8)|buffer[1];
  // ...解析各轴数据
}

抬手唤醒逻辑

c

Copy

void app_task_mpu6050(void *pvParameters) {
  while(1) {
    if(CheckHandUp()) { // 检测加速度变化
      xEventGroupSetBits(xDisplayEvent, DISPLAY_WAKEUP_BIT);
    }
    vTaskDelay(50); // 50ms检测周期
  }
}

四、多任务协同设计

4.1 任务间通信

消息队列应用(LED控制):

c

Copy

// 发送端(按键任务)
uint8_t led_cmd = LED_TOGGLE;
xQueueSend(xLEDQueue, &led_cmd, portMAX_DELAY);

// 接收端(LED任务)
xQueueReceive(xLEDQueue, &cmd, portMAX_DELAY);
GPIO_Toggle(LED_PORT, LED_PIN);
4.2 事件标志组应用

显示状态管理

c

Copy

// 定义事件位
#define DISPLAY_UPDATE_BIT (1 << 0)
#define DISPLAY_SLEEP_BIT  (1 << 1)

// 设置事件
xEventGroupSetBits(xDisplayGroup, DISPLAY_UPDATE_BIT);

// 等待事件
EventBits_t bits = xEventGroupWaitBits(xDisplayGroup, 
  DISPLAY_UPDATE_BIT | DISPLAY_SLEEP_BIT, 
  pdTRUE, pdFALSE, 100 / portTICK_RATE_MS);
4.3 资源保护(互斥锁)

c

Copy

SemaphoreHandle_t xPrintfMutex = xSemaphoreCreateMutex();

void SafePrintf(const char *format, ...) {
  xSemaphoreTake(xPrintfMutex, portMAX_DELAY);
  va_list args;
  va_start(args, format);
  vprintf(format, args);
  va_end(args);
  xSemaphoreGive(xPrintfMutex);
}

五、低功耗与稳定性

5.1 空闲任务钩子

c

Copy

void vApplicationIdleHook(void) {
  __WFI(); // 进入睡眠模式
}
5.2 看门狗配置

独立看门狗(文档23):

c

Copy

void IWDG_Init(uint32_t timeout_ms) {
  IWDG->KR = 0x5555; // 解锁PR/RLR寄存器
  IWDG->PR = 4;      // 预分频64 => 1.6ms/tick
  IWDG->RLR = timeout_ms * 625 / 1000;
  IWDG->KR = 0xAAAA; // 重载
  IWDG->KR = 0xCCCC; // 启动看门狗
}

喂狗任务

c

Copy

void Watchdog_Task(void *pv) {
  while(1) {
    IWDG_Refresh();
    vTaskDelay(2000); // 2秒喂狗
  }
}

六、开发经验总结

6.1 调试技巧
  1. 分段初始化:逐个启用外设,避免硬件冲突
  2. 利用RTOS跟踪工具:FreeRTOS+Trace可视化任务状态
  3. 内存监控:使用uxTaskGetStackHighWaterMark()检测栈溢出
6.2 常见问题
  1. I2C总线锁死
    • 增加超时重试机制
    • 硬件上拉电阻(4.7KΩ)
  2. 显示刷新撕裂
    • 使用双缓冲机制
    • 在垂直消隐期更新显存
  3. 传感器数据异常
    • 添加数字滤波(移动平均、卡尔曼滤波)
    • 数据合理性校验

七、项目扩展方向

  1. 增加GPS定位:UBLOX NEO-6M模块
  2. 无线充电功能:Qi标准接收电路
  3. 语音交互:集成LD3320语音识别芯片
  4. 运动算法优化:计步器、卡路里计算
  5. GUI升级:LVGL图形库移植

结语

通过本项目的实践,读者可以掌握以下核心技能:

  • FreeRTOS多任务设计与优化
  • 常见传感器驱动开发
  • 低功耗设计方法论
  • 嵌入式系统稳定性保障
  • 硬件/软件协同调试技巧

附录:硬件连接参考

模块 引脚 功能
MAX30102 PB6-PB7 I2C1
MPU6050 PB8-PB9 I2C2
OLED PD10-PD11 I2C3
BLE PB10-PB11 USART3
蜂鸣器 PF8 GPIO

网站公告

今日签到

点亮在社区的每一天
去签到