基于 STM32 单片机的远程老人监测系统设计

一、引言

1.1 研究背景与意义

随着人口老龄化进程的不断加快,空巢老人的数量日益增多。由于子女工作繁忙等原因,老人独自在家时的安全和健康状况难以得到实时关注,意外事件时有发生,如突发疾病、摔倒等,若不能及时发现和处理,可能会造成严重后果。

基于此,设计一款基于 STM32 单片机的远程老人监测系统具有重要的现实意义。该系统能够实时监测老人的身体状况、活动情况以及居住环境的安全信息,并将这些信息远程传输给子女或监护人员,使他们能够及时了解老人的情况,在发生意外时能够迅速采取措施。本系统采用 STM32 单片机作为主控制器,结合各类传感器和通信模块,具有成本低、性能稳定、操作简便等特点,能够为老人的安全和健康提供有力保障,缓解社会和家庭的养老压力,具有较好的应用价值和社会意义。

1.2 国内外研究现状

国内外在远程老人监测领域已开展了较多研究并取得了一定成果。国外的一些监测系统功能较为先进,例如能够通过可穿戴设备实时监测老人的心率、血压等生理参数,并结合人工智能算法进行健康风险评估,但这些系统往往成本较高,且在适应国内老人使用习惯和网络环境方面存在不足。

国内的研究更注重实用性和经济性,许多系统以单片机为核心,结合传感器和简单的通信模块实现基本的监测功能,如人体感应、烟雾检测等。然而,部分系统在监测参数的全面性、数据传输的稳定性以及报警的及时性等方面还有待提升。近年来,随着物联网技术的发展,为远程老人监测系统的升级提供了技术支持。与现有研究相比,本设计选用 STM32 单片机作为主控制器,具有更强的数据处理能力和接口扩展性;采用多种传感器集成的方式,实现对老人多方面状况的监测;通过无线通信模块实现数据的远程传输,确保信息传递的及时性和准确性。

1.3 研究目标与内容

本研究的目标是设计并实现一款基于 STM32 单片机的远程老人监测系统,该系统能够实时监测老人的心率、体温等生理参数,检测老人的活动状态和是否摔倒,监测居住环境的温湿度、烟雾等安全信息,并将监测数据远程发送到子女或监护人员的终端设备,在出现异常情况时能够及时发出报警信息。

研究内容主要包括以下几个方面:

  1. 系统总体设计:分析系统的功能需求,设计系统的整体架构和技术方案。
  1. 硬件设计:包括 STM32 最小系统设计、生理参数监测模块接口电路设计、人体活动与摔倒检测模块电路设计、环境监测模块电路设计、无线通信模块接口电路设计以及电源电路设计等。
  1. 软件设计:搭建软件开发环境,设计主程序流程,实现传感器数据采集与处理程序、数据远程传输程序、异常检测与报警程序等。
  1. 系统测试与优化:对系统的各项功能和性能进行测试,根据测试结果进行优化,确保系统稳定可靠运行。

二、系统总体设计方案

2.1 需求分析

用户对远程老人监测系统的功能需求主要包括以下几个方面:

  1. 生理参数监测功能:能够实时监测老人的心率、体温等基本生理参数,当参数超出正常范围时发出报警。
  1. 活动与摔倒检测功能:能够检测老人的活动状态,判断老人是否摔倒,在老人长时间未活动或发生摔倒时及时报警。
  1. 环境监测功能:实时监测老人居住环境的温湿度、烟雾浓度等信息,在环境异常时发出提醒。
  1. 远程数据传输功能:将监测到的各类数据实时传输到子女或监护人员的手机等终端设备,方便他们随时查看。
  1. 本地报警功能:当出现异常情况时,系统在本地发出声光报警,提醒老人或周围人员注意。
  1. 低功耗设计:系统应具有较低的功耗,以延长设备的续航时间,减少更换电池的频率。

基于以上需求,确定系统设计方向为:以 STM32 单片机为核心,通过生理参数传感器采集老人的心率、体温等数据,利用人体红外传感器和加速度传感器检测老人的活动状态和摔倒情况,通过温湿度传感器、烟雾传感器监测环境信息,采用无线通信模块将数据远程传输,同时设计本地报警模块和低功耗管理模块,实现系统的各项功能。

2.2 系统架构设计

系统整体架构主要由 STM32 单片机、生理参数监测模块、人体活动与摔倒检测模块、环境监测模块、无线通信模块、报警模块、电源模块等组成。

STM32 单片机作为主控制器,负责协调各个模块的工作。它通过相应的接口与生理参数监测模块连接,接收老人的生理参数数据;通过 GPIO 接口和 I2C/SPI 接口连接人体活动与摔倒检测模块,获取老人的活动状态和摔倒信息;通过单总线或 I2C 接口连接环境监测模块,采集环境温湿度、烟雾浓度等数据;通过 UART 接口连接无线通信模块,将各类监测数据远程发送出去,并接收终端设备的控制指令;通过 GPIO 接口连接报警模块,控制报警装置的工作。

生理参数监测模块由心率传感器和体温传感器组成,用于实时采集老人的心率和体温数据,并将数据传输给 STM32 单片机。

人体活动与摔倒检测模块包括人体红外传感器和加速度传感器。人体红外传感器用于检测老人是否在活动区域内活动,加速度传感器用于检测老人的运动状态,判断是否发生摔倒。

环境监测模块由温湿度传感器(如 DHT11)和烟雾传感器(如 MQ-2)组成,用于采集老人居住环境的温湿度和烟雾浓度数据,为老人提供安全的居住环境监测。

无线通信模块采用 GPRS 模块或 WiFi 模块,通过无线网络将 STM32 单片机处理后的监测数据发送到远程服务器或子女的终端设备,实现数据的远程传输。

报警模块由蜂鸣器和 LED 灯组成,当系统检测到异常情况时,蜂鸣器发出声音报警,LED 灯闪烁发出光报警,实现本地报警功能。

电源模块为系统中的各个组件提供稳定的工作电压,采用锂电池供电,并设计低功耗管理电路,延长设备的使用时间。

2.3 技术路线选择

  1. 单片机选型:选择 STM32 单片机作为主控制器,原因在于其具有强大的处理能力,能够快速处理多传感器的数据和实现复杂的控制逻辑;丰富的外设接口,便于与各类传感器、通信模块等进行连接;同时,STM32 系列单片机支持低功耗模式,能够满足系统的低功耗设计需求。与 51 单片机相比,STM32 的性能更优,处理速度更快;与其他高端处理器相比,STM32 成本适中,性价比更高,适合本系统的设计。
  1. 生理参数传感器选型:心率传感器选用 MAX30102,该传感器集成了红光和红外光 LED,能够非接触式地检测心率和血氧饱和度,精度较高,且功耗较低;体温传感器选用 DS18B20,采用单总线通信,精度能满足需求,接口简单,便于与 STM32 单片机连接。
  1. 人体活动与摔倒检测传感器选型:人体红外传感器选用 HC-SR501,能够检测人体的移动,灵敏度可调;加速度传感器选用 MPU6050,它集成了三轴加速度计和三轴陀螺仪,能够准确检测物体的运动状态和姿态变化,适合用于摔倒检测。
  1. 环境传感器选型:温湿度传感器选用 DHT11,成本低、接口简单,能够满足室内环境温湿度监测的需求;烟雾传感器选用 MQ-2,对烟雾和可燃气体具有较高的灵敏度,适合用于家庭环境的安全监测。
  1. 无线通信模块选型:根据实际应用场景选择合适的通信模块,若老人家中有 WiFi 网络,可选用 ESP8266 WiFi 模块,成本较低,数据传输速度快;若没有 WiFi 网络,可选用 GPRS 模块(如 SIM800L),通过移动网络进行通信,覆盖范围广。

三、系统硬件设计

3.1 STM32 最小系统设计

本系统选用 STM32L051 系列单片机作为主控制器,该系列单片机具有低功耗特性,适合电池供电的设备。STM32 最小系统主要由电源电路、时钟电路、复位电路和下载接口电路等组成。

电源电路:STM32L051 单片机工作电压为 1.8V-3.6V,系统采用 3.7V 锂电池供电,通过低压差线性稳压器(如 TC1185-3.3V)将电压稳定在 3.3V,为单片机及其他需要 3.3V 电压的模块供电。电源电路中加入了滤波电容,以减小电源噪声对系统的影响,同时设计了电池电量检测电路,便于监测电池剩余电量。

时钟电路:STM32L051 单片机采用内部高速时钟(HSI)作为主要时钟源,其频率为 16MHz,可满足系统的基本计时和数据处理需求。同时,也可根据需要外接 32.768kHz 的实时时钟(RTC)晶体振荡器,用于精确计时。

复位电路:采用上电复位和手动复位相结合的方式。上电复位通过 RC 电路实现,确保系统上电时能够正确复位;手动复位通过复位按钮实现,方便在系统出现异常时进行复位操作。

下载接口电路:采用 SWD 接口,通过下载器将程序下载到 STM32 单片机中,该接口占用 IO 资源少,便于系统的小型化设计。

3.2 生理参数监测模块电路设计

  1. 心率监测电路:MAX30102 心率传感器工作电压为 3.3V,通过 I2C 接口与 STM32 单片机连接。传感器的 SDA 引脚连接到单片机的 I2C_SDA 引脚,SCL 引脚连接到单片机的 I2C_SCL 引脚,INT 引脚连接到单片机的 GPIO 引脚,用于输出中断信号。在电路中,为传感器的电源引脚添加滤波电容,以保证供电稳定;在 I2C 总线上添加上拉电阻,确保通信的可靠性。
  1. 体温监测电路:DS18B20 体温传感器采用单总线通信方式,工作电压为 3.3V。传感器的 DATA 引脚通过一个 4.7kΩ 的上拉电阻连接到 STM32 单片机的 GPIO 引脚,同时连接到 3.3V 电源。上拉电阻保证了 DATA 引脚在空闲状态时为高电平,确保通信的稳定。

生理参数监测模块的工作原理是:MAX30102 传感器通过检测人体血液对红光和红外光的吸收变化,计算出心率数据;DS18B20 传感器通过检测自身温度敏感元件的电阻变化,测量出人体体温;这些数据通过相应的接口传输给 STM32 单片机进行处理。

3.3 人体活动与摔倒检测模块电路设计

  1. 人体活动检测电路:HC-SR501 人体红外传感器工作电压为 3.3V-5V,本系统中采用 3.3V 供电。传感器的输出引脚连接到 STM32 单片机的 GPIO 引脚,当检测到人体活动时,输出高电平;当检测不到人体活动时,输出低电平。电路中可通过调节传感器的灵敏度和检测距离旋钮,适应不同的使用环境。
  1. 摔倒检测电路:MPU6050 加速度传感器工作电压为 3.3V,通过 I2C 接口与 STM32 单片机连接。传感器的 SDA 引脚连接到单片机的 I2C_SDA 引脚,SCL 引脚连接到单片机的 I2C_SCL 引脚,INT 引脚连接到单片机的 GPIO 引脚,用于输出运动状态中断信号。电路中为传感器的电源引脚添加滤波电容,I2C 总线上添加上拉电阻,确保传感器稳定工作和通信可靠。

人体活动与摔倒检测模块的工作原理是:HC-SR501 传感器通过检测人体发出的红外线变化,判断老人是否在活动;MPU6050 传感器通过检测加速度和角速度的变化,分析老人的运动姿态,当检测到符合摔倒特征的运动时,向单片机发送中断信号。

3.4 环境监测模块电路设计

  1. 温湿度监测电路:DHT11 温湿度传感器采用单总线通信方式,工作电压为 3.3V。传感器的 DATA 引脚通过 4.7kΩ 的上拉电阻连接到 STM32 单片机的 GPIO 引脚,同时连接到 3.3V 电源。其工作原理是通过内部的温湿度敏感元件采集环境数据,并通过单总线将数据传输给单片机。
  1. 烟雾监测电路:MQ-2 烟雾传感器工作电压为 5V,需要通过 ADC 接口与 STM32 单片机连接。传感器的输出引脚连接到单片机的 ADC 输入引脚,同时通过一个滑动变阻器调节输出电压的范围。电路中还设计了加热电路,为传感器提供稳定的工作温度。MQ-2 传感器通过检测烟雾或可燃气体对其内部气敏元件电导率的影响,输出相应的电压信号,单片机通过 ADC 转换获取烟雾浓度数据。

3.5 无线通信模块电路设计

若选用 ESP8266 WiFi 模块,其工作电压为 3.3V,通过 UART 接口与 STM32 单片机连接。模块的 TX 引脚连接到单片机的 USART_RX 引脚,RX 引脚连接到单片机的 USART_TX 引脚,RST 引脚连接到单片机的 GPIO 引脚,用于控制模块的复位。电路中为模块的电源引脚添加滤波电容,在 UART 通信线上添加限流电阻,减少信号干扰。

若选用 SIM800L GPRS 模块,其工作电压为 3.4V-4.4V,需要通过电源管理电路从锂电池获取合适的电压。模块通过 UART 接口与 STM32 单片机连接,同时需要插入 SIM 卡以实现网络连接。电路中设计了 SIM 卡接口电路和天线接口电路,确保模块能够正常进行无线通信。

无线通信模块的工作原理是:STM32 单片机将处理后的监测数据按照一定的格式打包,通过 UART 接口发送给通信模块,通信模块将数据通过无线网络发送到远程服务器或指定的终端设备,实现数据的远程传输。

3.6 报警模块与电源模块电路设计

  1. 报警模块电路:报警模块由蜂鸣器和 LED 灯组成。蜂鸣器采用有源蜂鸣器,工作电压为 3.3V,其正极通过三极管连接到 STM32 单片机的 GPIO 引脚,负极接地。当单片机输出高电平时,三极管导通,蜂鸣器发声。LED 灯的正极通过限流电阻连接到单片机的 GPIO 引脚,负极接地,当单片机输出高电平时,LED 灯点亮。
  1. 电源模块电路:采用 3.7V 锂电池作为系统的供电电源,容量根据系统的功耗需求选择。电源模块中设计了充电电路,通过 Micro USB 接口为锂电池充电,同时加入了过充、过放保护电路,保护锂电池的安全。通过低压差线性稳压器为不同电压需求的模块提供稳定的工作电压,并设计了电源开关,方便系统的开启和关闭。

四、系统软件设计

4.1 软件开发环境搭建

本系统的软件开发环境采用 Keil MDK 5,它支持 STM32 系列单片机的程序开发,具有丰富的库函数和调试功能。

搭建开发环境的步骤如下:

  1. 安装 Keil MDK 5 软件:从官方网站下载安装包,按照安装向导进行安装,在安装过程中输入有效的许可证信息。
  1. 安装 STM32 芯片支持包:打开 Keil MDK 5 软件,进入 Pack Installer,搜索并下载安装 STM32L051 系列芯片的支持包,以确保软件能够正确识别和配置所使用的单片机。
  1. 配置编译器和调试器:在工程设置中,选择 ARMCC 编译器,配置相应的优化等级;根据所使用的调试工具(如 ST-Link),在 Debug 选项中选择对应的调试器,并设置调试接口和通信速率等参数,以便进行程序的下载和在线调试。

4.2 主程序流程设计

主程序是系统的核心,负责协调各个模块的工作,其工作流程如下:

系统上电后,首先进行初始化操作,包括 STM32 单片机的初始化(时钟、GPIO、I2C、UART、ADC、RTC 等)、生理参数监测模块的初始化、人体活动与摔倒检测模块的初始化、环境监测模块的初始化、无线通信模块的初始化、报警模块的初始化以及系统参数的初始化(如各类参数的正常阈值、采样周期等)。

初始化完成后,系统进入低功耗模式,以节省电量。当到达设定的采样周期或有中断事件发生(如传感器检测到异常)时,系统被唤醒,进入工作模式。

在工作模式下,系统依次采集各传感器的数据:

  1. 采集心率传感器和体温传感器的数据,进行处理和判断,若超出正常范围,设置生理参数异常标志。
  1. 采集人体红外传感器和加速度传感器的数据,分析老人的活动状态和是否摔倒,若长时间未活动或发生摔倒,设置活动异常标志。
  1. 采集温湿度传感器和烟雾传感器的数据,判断环境是否异常,若超出设定阈值,设置环境异常标志。

系统将采集到的各类数据进行打包处理,通过无线通信模块发送到远程终端。若检测到任何异常标志,控制报警模块发出本地声光报警,并在发送的数据中标记异常类型。

数据发送完成后,系统清除相应的标志位,再次进入低功耗模式,等待下一次唤醒。

4.3 传感器数据采集与处理程序设计

  1. 生理参数数据采集与处理:通过 I2C 接口与 MAX30102 传感器通信,配置传感器的工作模式和采样率,读取心率原始数据,经过滤波、峰值检测等算法处理后得到心率值;通过单总线与 DS18B20 传感器通信,发送温度转换指令,读取温度数据,转换为实际体温值。将处理后的心率和体温值与预设的正常范围进行比较,判断是否异常。
cpp 复制代码
#include "stm32l051xx.h"
#include <stdint.h>
#include <string.h>
// 设计加V:Niumajiuhao
// 传感器引脚定义
#define MAX30102_SDA_PIN GPIO_PIN_0
#define MAX30102_SCL_PIN GPIO_PIN_1
#define MAX30102_INT_PIN GPIO_PIN_2
#define DS18B20_PIN      GPIO_PIN_3
#define HC_SR501_PIN     GPIO_PIN_4
#define MPU6050_SDA_PIN  GPIO_PIN_5
#define MPU6050_SCL_PIN  GPIO_PIN_6
#define MPU6050_INT_PIN  GPIO_PIN_7
#define DHT11_PIN        GPIO_PIN_8
#define MQ2_PIN          GPIO_PIN_9
#define ESP8266_TX_PIN   GPIO_PIN_10
#define ESP8266_RX_PIN   GPIO_PIN_11
#define BUZZER_PIN       GPIO_PIN_12
#define LED_PIN          GPIO_PIN_13

// 系统参数定义
#define NORMAL_HEART_MIN 60
#define NORMAL_HEART_MAX 100
#define NORMAL_TEMP_MIN  36.0f
#define NORMAL_TEMP_MAX  37.2f
#define INACTIVITY_THRESHOLD 300  // 5分钟未活动阈值(秒)
#define TEMP_HIGH_THRESHOLD 30.0f
#define TEMP_LOW_THRESHOLD 10.0f
#define HUMIDITY_HIGH_THRESHOLD 80.0f
#define SMOKE_THRESHOLD 500       // 烟雾浓度阈值

// 全局变量定义
float heartRate = 0.0f;
float temperature = 0.0f;
float envTemp = 0.0f;
float humidity = 0.0f;
uint16_t smokeValue = 0;
uint8_t fallDetected = 0;
uint32_t inactivityTime = 0;
uint8_t systemStatus = 0;  // 0-正常,1-生理异常,2-活动异常,3-环境异常

// 函数声明
void SystemClock_Config(void);
void GPIO_Init(void);
void I2C_Init(void);
void USART_Init(void);
void ADC_Init(void);
void RTC_Init(void);
void LowPower_Init(void);

void MAX30102_Init(void);
float MAX30102_ReadHeartRate(void);
float DS18B20_ReadTemperature(void);
uint8_t HC_SR501_CheckActivity(void);
void MPU6050_Init(void);
uint8_t MPU6050_CheckFall(void);
void DHT11_ReadData(float *temp, float *hum);
uint16_t MQ2_ReadValue(void);

void ESP8266_SendData(void);
void Alarm_Trigger(void);
void Alarm_Stop(void);

void Delay_Ms(uint32_t ms);
uint32_t GetTick(void);

// 主函数
int main(void) {
    // 系统初始化
    SystemInit();
    SystemClock_Config();
    GPIO_Init();
    I2C_Init();
    USART_Init();
    ADC_Init();
    RTC_Init();
    LowPower_Init();
    
    // 传感器初始化
    MAX30102_Init();
    MPU6050_Init();
    
    // 系统状态初始化
    uint32_t lastSampleTime = 0;
    const uint32_t sampleInterval = 5000;  // 5秒采样间隔
    
    while (1) {
        // 定时采样
        if (GetTick() - lastSampleTime >= sampleInterval) {
            lastSampleTime = GetTick();
            
            // 采集生理参数
            heartRate = MAX30102_ReadHeartRate();
            temperature = DS18B20_ReadTemperature();
            
            // 采集活动状态
            uint8_t activity = HC_SR501_CheckActivity();
            if (activity) {
                inactivityTime = 0;
            } else {
                inactivityTime += sampleInterval / 1000;
            }
            
            // 检测摔倒
            fallDetected = MPU6050_CheckFall();
            
            // 采集环境参数
            DHT11_ReadData(&envTemp, &humidity);
            smokeValue = MQ2_ReadValue();
            
            // 异常检测
            systemStatus = 0;
            if (heartRate < NORMAL_HEART_MIN || heartRate > NORMAL_HEART_MAX || 
                temperature < NORMAL_TEMP_MIN || temperature > NORMAL_TEMP_MAX) {
                systemStatus |= 1;  // 生理异常
            }
            
            if (fallDetected || inactivityTime >= INACTIVITY_THRESHOLD) {
                systemStatus |= 2;  // 活动异常
            }
            
            if (envTemp > TEMP_HIGH_THRESHOLD || envTemp < TEMP_LOW_THRESHOLD || 
                humidity > HUMIDITY_HIGH_THRESHOLD || smokeValue > SMOKE_THRESHOLD) {
                systemStatus |= 4;  // 环境异常
            }
            
            // 异常报警
            if (systemStatus != 0) {
                Alarm_Trigger();
            } else {
                Alarm_Stop();
            }
            
            // 发送数据
            ESP8266_SendData();
        }
        
        // 低功耗模式
        if (systemStatus == 0) {
            // 进入停止模式
            PWR->CR |= PWR_CR_LPSDSR;
            SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
            __WFI();
        }
    }
}

// 系统时钟配置
void SystemClock_Config(void) {
    RCC->CR |= RCC_CR_HSION;
    while (!(RCC->CR & RCC_CR_HSIRDY));
    
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    PWR->CR |= PWR_CR_VOS_0;
    
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV1;
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
    
    RCC->CFGR |= RCC_CFGR_SW_HSI;
    while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI);
    
    FLASH->ACR |= FLASH_ACR_PRFTEN | FLASH_ACR_LATENCY;
}

// GPIO初始化
void GPIO_Init(void) {
    RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
    
    // 配置I2C引脚
    GPIOA->MODER |= GPIO_MODER_MODE0_1 | GPIO_MODER_MODE1_1;
    GPIOA->AFR[0] |= (1 << (0*4)) | (1 << (1*4));
    GPIOA->OTYPER |= GPIO_OTYPER_OT0 | GPIO_OTYPER_OT1;
    
    // 配置输入引脚
    GPIOA->MODER &= ~(GPIO_MODER_MODE2 | GPIO_MODER_MODE3 | GPIO_MODER_MODE4 | 
                     GPIO_MODER_MODE7 | GPIO_MODER_MODE8);
    GPIOA->PUPDR |= GPIO_PUPDR_PUPD2_0 | GPIO_PUPDR_PUPD3_0 | 
                   GPIO_PUPDR_PUPD4_0 | GPIO_PUPDR_PUPD7_0 | GPIO_PUPDR_PUPD8_0;
    
    // 配置USART引脚
    GPIOA->MODER |= GPIO_MODER_MODE10_1 | GPIO_MODER_MODE11_1;
    GPIOA->AFR[1] |= (1 << ((10-8)*4)) | (1 << ((11-8)*4));
    
    // 配置ADC引脚
    GPIOA->MODER |= GPIO_MODER_MODE9_1;
    
    // 配置输出引脚
    GPIOA->MODER |= GPIO_MODER_MODE12_0 | GPIO_MODER_MODE13_0;
    GPIOA->OTYPER &= ~(GPIO_OTYPER_OT12 | GPIO_OTYPER_OT13);
}

// I2C初始化
void I2C_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
    
    I2C1->CR1 &= ~I2C_CR1_PE;
    I2C1->TIMINGR = 0x00201D2B;  // 100kHz @ 16MHz
    I2C1->CR1 |= I2C_CR1_PE;
}

// USART初始化
void USART_Init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
    
    USART1->BRR = 16000000 / 9600;
    USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}

// ADC初始化
void ADC_Init(void) {
    RCC->APB2ENR |= RCC_APB2ENR_ADCEN;
    
    ADC1->CR = 0;
    ADC1->CFGR1 = ADC_CFGR1_RES_1;  // 8位分辨率
    ADC1->CHSELR = ADC_CHSELR_CHSEL9;  // 选择通道9
    ADC1->CR |= ADC_CR_ADEN;
    while (!(ADC1->ISR & ADC_ISR_ADRDY));
}

// RTC初始化
void RTC_Init(void) {
    RCC->APB1ENR |= RCC_APB1ENR_RTCEN;
    RCC->CSR |= RCC_CSR_LSION;
    while (!(RCC->CSR & RCC_CSR_LSIRDY));
    RCC->RTCCLKSOURCE = RCC_RTCCLKSOURCE_LSI;
    RCC->CSR |= RCC_CSR_RTCEN;
    
    RTC->WPR = 0xCA;
    RTC->WPR = 0x53;
    RTC->ISR |= RTC_ISR_INIT;
    while (!(RTC->ISR & RTC_ISR_INITF));
    
    RTC->PRER = 0x7F << 16 | 0xFF;  // 1Hz
    RTC->ISR &= ~RTC_ISR_INIT;
}

// 低功耗初始化
void LowPower_Init(void) {
    PWR->CR |= PWR_CR_LPRUN;
    PWR->CR |= PWR_CR_CWUF;
}

// MAX30102初始化
void MAX30102_Init(void) {
    // 初始化代码省略,实际应用中需要根据数据手册配置
}

// 读取心率
float MAX30102_ReadHeartRate(void) {
    // 模拟读取心率,实际应用中需要根据传感器数据计算
    static uint32_t count = 0;
    count++;
    return 70 + (count % 20);  // 生成60-100之间的模拟数据
}

// 读取温度
float DS18B20_ReadTemperature(void) {
    // 模拟读取温度,实际应用中需要实现单总线通信
    static uint32_t count = 0;
    count++;
    return 36.5f + (count % 10) * 0.1f;  // 生成36.5-37.4之间的模拟数据
}

// 检测活动状态
uint8_t HC_SR501_CheckActivity(void) {
    return (GPIOA->IDR & HC_SR501_PIN) ? 1 : 0;
}

// MPU6050初始化
void MPU6050_Init(void) {
    // 初始化代码省略,实际应用中需要根据数据手册配置
}

// 检测摔倒
uint8_t MPU6050_CheckFall(void) {
    // 模拟摔倒检测,实际应用中需要根据加速度数据判断
    static uint32_t count = 0;
    count++;
    return (count % 100 == 0) ? 1 : 0;  // 偶尔模拟一次摔倒
}

// 读取温湿度
void DHT11_ReadData(float *temp, float *hum) {
    // 模拟读取温湿度,实际应用中需要实现单总线通信
    static uint32_t count = 0;
    count++;
    *temp = 25.0f + (count % 10) * 0.5f;
    *hum = 50.0f + (count % 30);
}

// 读取烟雾浓度
uint16_t MQ2_ReadValue(void) {
    // 模拟读取烟雾浓度,实际应用中需要实现ADC读取
    static uint32_t count = 0;
    count++;
    return 300 + (count % 200);  // 生成300-500之间的模拟数据
}

// 发送数据到服务器
void ESP8266_SendData(void) {
    char data[256];
    sprintf(data, "AT+CIPSTART=\"TCP\",\"your_server_ip\",your_server_port\r\n");
    for (uint8_t i = 0; i < strlen(data); i++) {
        while (!(USART1->ISR & USART_ISR_TXE));
        USART1->TDR = data[i];
    }
    
    Delay_Ms(1000);
    
    sprintf(data, "{\"heartRate\":%.1f,\"temperature\":%.1f,\"envTemp\":%.1f,"
                  "\"humidity\":%.1f,\"smoke\":%d,\"fall\":%d,\"inactivity\":%d,"
                  "\"status\":%d}\r\n",
            heartRate, temperature, envTemp, humidity, smokeValue,
            fallDetected, inactivityTime, systemStatus);
    
    sprintf(data, "AT+CIPSEND=%d\r\n", strlen(data));
    for (uint8_t i = 0; i < strlen(data); i++) {
        while (!(USART1->ISR & USART_ISR_TXE));
        USART1->TDR = data[i];
    }
    
    Delay_Ms(500);
    
    for (uint8_t i = 0; i < strlen(data); i++) {
        while (!(USART1->ISR & USART_ISR_TXE));
        USART1->TDR = data[i];
    }
}

// 触发报警
void Alarm_Trigger(void) {
    GPIOA->BSRR = BUZZER_PIN | LED_PIN;
}

// 停止报警
void Alarm_Stop(void) {
    GPIOA->BSRR = (BUZZER_PIN | LED_PIN) << 16;
}

// 毫秒延时
void Delay_Ms(uint32_t ms) {
    uint32_t ticks = ms * (SystemCoreClock / 10000);
    while (ticks--);
}

// 获取系统运行时间(毫秒)
uint32_t GetTick(void) {
    static uint32_t tick = 0;
    static uint32_t lastRtc = RTC->TR;
    uint32_t currentRtc = RTC->TR;
    
    if (currentRtc != lastRtc) {
        tick += 1000;
        lastRtc = currentRtc;
    }
    return tick;
}

// 中断服务函数
void EXTI0_1_IRQHandler(void) {
    if (EXTI->PR & MAX30102_INT_PIN) {
        EXTI->PR |= MAX30102_INT_PIN;
        // 处理MAX30102中断
    }
}

void EXTI2_3_IRQHandler(void) {
    if (EXTI->PR & MPU6050_INT_PIN) {
        EXTI->PR |= MPU6050_INT_PIN;
        fallDetected = 1;
    }
}