基于STM32与物联网的智能监护系统:从传感器到云端的完整实现
2026/9/8 4:12:47 网站建设 项目流程

最近在做一个社区关怀项目,需要为独居老人设计一套低成本、易部署的居家监护方案。核心需求是能实时监测老人的活动状态,并在异常时及时通知家人。经过一番选型,最终决定基于STM32微控制器来搭建这套系统,因为它兼具了性能、功耗和丰富的生态支持。本文将完整分享从硬件选型、软件设计到云端联调的全过程,手把手教你打造一个功能完整的“基于STM32的独居老人监护系统”。无论你是嵌入式新手想练手,还是正在寻找实际项目方案的开发者,都能从中获得可直接复用的代码和配置。

1. 系统背景与核心设计思路

随着社会老龄化加剧,独居老人的安全与健康监护成为一个日益突出的社会问题。传统的定期上门探望或电话问候存在时间盲区,无法做到24小时不间断的守护。因此,利用物联网技术构建智能监护系统,实现非侵入式的实时监测与预警,具有重要的现实意义。

本系统的核心设计目标是:低成本、低功耗、易用、可靠。我们选择STM32F103C8T6(俗称“蓝桥杯”或“最小系统板”)作为主控,它价格低廉、资源丰富,足以胜任本项目的需求。系统通过多种传感器采集环境与人体活动数据,经由WiFi模块上传至云端平台(如机智云),家属可通过手机APP远程查看状态并接收报警信息。

系统核心功能模块包括:

  1. 环境监测:使用DHT11温湿度传感器监测室内环境。
  2. 活动感知:使用HC-SR501人体红外传感器(PIR)监测老人是否在活动区域出现。
  3. 紧急呼叫:设置一个物理按键,供老人在紧急情况下主动触发报警。
  4. 本地显示:使用0.96寸OLED显示屏(SSD1306驱动)实时显示传感器数据、系统状态和时间。
  5. 无线通信:使用ESP8266 WiFi模块(AT指令固件)连接家庭路由器,将数据上传至云端。
  6. 云端与远程通知:数据上传至机智云IoT平台,平台可配置报警规则,并通过APP推送或短信通知家属。

整个系统的数据流如下图所示(概念流程):

传感器数据(DHT11, PIR) -> STM32 (采集、处理、逻辑判断) -> UART -> ESP8266 (WiFi传输) -> 路由器 -> 机智云服务器 -> 家属手机APP OLED显示 <--| |--> 云端报警规则触发 -> 推送通知 紧急按键 --|

2. 硬件准备与开发环境搭建

2.1 硬件清单与连接

以下是本项目所需的核心硬件组件及简要说明:

组件型号/说明关键接口备注
主控MCUSTM32F103C8T6 最小系统板GPIO, USART, I2C核心处理器,也可用其他F1系列型号
WiFi模块ESP-01S (ESP8266)UART (TX/RX)负责网络通信,需烧录AT固件
温湿度传感器DHT11单总线 (GPIO)测量室内温湿度
人体红外传感器HC-SR501GPIO检测人体移动,输出高低电平
显示模块0.96寸 OLED (I2C接口, SSD1306)I2C (SCL, SDA)用于本地信息显示
紧急按键轻触开关GPIO (外部中断)用于老人主动报警
其他杜邦线、面包板、USB转TTL、电阻等-用于连接与调试

核心连接示意图(基于STM32F103C8T6):

  • ESP8266 (ESP-01S):
    • VCC-> 3.3V (注意:必须接3.3V!)
    • GND-> GND
    • TX-> STM32的PA3(USART2_RX)
    • RX-> STM32的PA2(USART2_TX)
    • CH_PD-> 3.3V
    • GPIO0-> 悬空或接高电平(运行模式)
  • OLED (I2C):
    • VCC-> 3.3V
    • GND-> GND
    • SCL-> STM32的PB6(I2C1_SCL)
    • SDA-> STM32的PB7(I2C1_SDA)
  • DHT11:
    • VCC-> 3.3V
    • GND-> GND
    • DATA-> STM32的PA1(GPIO)
  • HC-SR501:
    • VCC-> 5V (该模块通常需要5V供电)
    • GND-> GND
    • OUT-> STM32的PA0(GPIO)
  • 紧急按键:
    • 一端接GND,另一端接STM32的PA8(GPIO),并在PA8与3.3V之间接一个10K上拉电阻。

2.2 软件开发环境

  1. IDE/工具链:

    • Keil uVision5 (MDK-ARM): 主流的STM32开发IDE。确保已安装对应STM32F1系列的Device Family Pack。
    • STM32CubeMX强烈推荐使用。用于图形化配置引脚、时钟、外设,并生成初始化代码框架,能极大提高开发效率,避免底层配置错误。
    • 串口调试助手: 如XCOM、SSCOM,用于调试ESP8266的AT指令和查看系统打印日志。
    • 机智云开发者中心: 用于创建产品、定义数据点、获取设备通信密钥。
  2. 固件库:

    • HAL库: 本项目使用STM32CubeMX生成的HAL库代码。HAL库抽象程度高,可移植性好,适合快速开发。
    • OLED/传感器驱动: 需要准备或编写SSD1306 OLED的I2C驱动、DHT11的单总线驱动。
  3. 版本说明:

    • STM32CubeMX版本: V6.x 均可。
    • Keil uVision5版本: V5.3x 及以上。
    • HAL库版本: 随CubeMX安装即可,本文不依赖特定小版本。
    • ESP8266 AT固件版本: 建议使用安信可官方发布的AT固件(如AT version:1.7.0.0及以上),稳定性较好。

3. 核心模块驱动与原理

在开始整合系统前,我们需要先搞定各个传感器和模块的驱动。这是整个项目的基石。

3.1 OLED显示模块驱动 (SSD1306, I2C)

0.96寸OLED屏是信息展示的窗口,我们通过I2C协议驱动它。首先需要编写基本的画点、画线、显示字符和字符串的函数。

核心驱动文件oled.c/oled.h要点:

// oled.h 部分定义 #define OLED_I2C_ADDRESS 0x78 // SSD1306的I2C地址,通常是0x78或0x7A #define OLED_WIDTH 128 #define OLED_HEIGHT 64 void OLED_Init(void); // 初始化OLED void OLED_Clear(void); // 清屏 void OLED_ShowChar(uint8_t x, uint8_t y, char chr); // 在指定坐标显示一个字符 void OLED_ShowString(uint8_t x, uint8_t y, char *str); // 显示字符串 void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len); // 显示数字 void OLED_Refresh(void); // 更新显存到屏幕

初始化流程:

  1. 配置STM32的I2C1(PB6, PB7)为标准模式,速度100kHz或400kHz。
  2. 向OLED发送一系列初始化命令序列(可在商家例程中找到),设置对比度、扫描方式、开启显示等。
  3. 在STM32内部维护一个OLED_GRAM[128][8]的显存数组,所有绘图操作先修改这个数组。
  4. 调用OLED_Refresh()时,将整个显存通过I2C一次性发送给OLED。

main.c中的简单使用示例:

OLED_Init(); OLED_Clear(); OLED_ShowString(0, 0, "Temp:"); OLED_ShowNum(40, 0, 25, 2); OLED_ShowString(60, 0, "C"); OLED_Refresh();

3.2 DHT11温湿度传感器驱动

DHT11是一款单总线数字温湿度传感器,通信时序要求严格。

驱动关键点:

  • 单总线协议: 同一根数据线用于双向通信。STM32需要先拉低总线至少18ms(起始信号),然后释放并等待DHT11响应。
  • 数据格式: DHT11一次传输40位数据(8bit湿度整数+8bit湿度小数+8bit温度整数+8bit温度小数+8bit校验和)。小数部分通常为0。
  • 时序读取: DHT11通过高低电平的持续时间来表示‘0’(26~28us高电平)和‘1’(70us高电平)。需要使用微秒级延时函数和精准的时序判断。
// dht11.c 中的数据读取函数框架 uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi) { uint8_t buf[5]; uint8_t i, j; // 1. 主机拉低至少18ms DHT11_IO_OUT(); DHT11_DQ_OUT(0); delay_ms(20); DHT11_DQ_OUT(1); delay_us(30); // 2. 切换为输入模式,等待DHT11响应 DHT11_IO_IN(); // ... 检查响应信号 ... // 3. 读取40位数据 for(j=0; j<5; j++) { for(i=0; i<8; i++) { // ... 等待低电平结束 ... delay_us(40); // 延时40us后检测电平 if(DHT11_DQ_IN() == 1) { buf[j] |= (1 << (7-i)); while(DHT11_DQ_IN() == 1); // 等待高电平结束 } } } // 4. 校验和检查 if(buf[4] == (buf[0]+buf[1]+buf[2]+buf[3])) { *humi = buf[0]; *temp = buf[2]; return 1; // 成功 } return 0; // 失败 }

3.3 HC-SR501人体红外传感器

这个模块使用非常简单,它是一个数字输出传感器。当检测到人体移动时,输出高电平(或可设置),否则输出低电平。我们只需要配置一个GPIO口为输入模式,周期性读取其电平状态即可。

// 初始化 GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; // 上拉,默认高电平,触发时模块输出低电平则改为PULLDOWN HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 读取状态 uint8_t pir_state = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); if(pir_state == GPIO_PIN_SET) { // 检测到活动 OLED_ShowString(0, 3, "Motion: Yes "); } else { // 无活动 OLED_ShowString(0, 3, "Motion: No "); }

3.4 ESP8266 WiFi模块通信 (AT指令)

ESP8266通过串口与STM32通信,使用AT指令集控制。这是连接云端的关键。

基础AT指令流程:

  1. 测试通信AT-> 回复OK
  2. 设置模式AT+CWMODE=1-> 设置为Station模式(连接路由器)
  3. 连接WiFiAT+CWJAP="你的WiFi名","你的WiFi密码"-> 回复WIFI CONNECTEDWIFI GOT IP
  4. 连接机智云服务器AT+CIPSTART="TCP","m2m.gizwits.com",80(或AT+CIPSTART="SSL","m2m.gizwits.com",8883用于加密)
  5. 发送数据AT+CIPSEND=<长度>-> 收到>后,发送具体的协议数据。

我们需要在STM32上实现一个稳定的AT指令发送与解析函数。关键点在于处理串口接收中断,使用状态机解析OKERROR以及IPD数据。

// esp8266.c 中的发送指令并等待回复函数示例 ESP8266_StatusTypeDef ESP8266_SendCmdAndWaitResp(uint8_t *cmd, uint8_t *expect_resp, uint32_t timeout) { USART_ClearRxBuffer(); // 清空接收缓冲区 USART_SendString(cmd); // 发送AT指令 return USART_WaitForString(expect_resp, timeout); // 等待指定字符串,超时返回错误 } // 在主循环或初始化中调用 void WiFi_Init(void) { delay_ms(1000); // 上电后等待模块稳定 if(ESP8266_SendCmdAndWaitResp("AT\r\n", "OK", 1000) != ESP8266_OK) { OLED_ShowString(0, 6, "WiFi: AT Fail"); return; } OLED_ShowString(0, 6, "WiFi: AT OK "); // ... 后续连接WiFi和服务器 }

4. 系统整合与业务逻辑实现

当所有模块驱动调试通过后,就可以开始编写主程序业务逻辑了。

4.1 使用STM32CubeMX生成工程框架

  1. 打开STM32CubeMX,选择MCU型号STM32F103C8Tx
  2. 配置时钟: 在RCC中,将HSE设置为Crystal/Ceramic Resonator。在Clock Configuration标签页,将系统时钟源设置为HSE,并将主频设置为72MHz(STM32F103的最高频率)。
  3. 配置GPIO
    • PA1: 输出模式(初始化时),用于控制DHT11总线。
    • PA0: 输入模式,用于读取HC-SR501。
    • PA8: 外部中断模式,下降沿触发(按键按下接地),用于紧急呼叫。
  4. 配置I2C1: 模式选择I2C,保持默认设置。
  5. 配置USART2: 异步模式,波特率115200(与ESP8266默认一致)。
  6. 配置SYS: Debug选择Serial Wire(如果要用ST-Link调试)。
  7. 生成代码: 设置好工程路径、名称、选择MDK-ARM,然后生成代码。

4.2 主程序逻辑设计

主程序采用前后台(超级循环)架构,在main函数的while(1)循环中周期性执行数据采集、显示和上报任务。紧急按键采用外部中断实现即时响应。

main.c核心逻辑结构:

// 全局变量定义 uint8_t temperature, humidity; uint8_t motion_detected; uint32_t last_upload_time = 0; uint32_t last_motion_time = 0; #define UPLOAD_INTERVAL 10000 // 数据上传间隔10秒 #define MOTION_TIMEOUT 300000 // 无活动超时时间5分钟 (300秒) int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); MX_USART2_UART_Init(); // 初始化各模块 OLED_Init(); DHT11_Init(); ESP8266_Init(); // 内部包含WiFi连接和服务器连接 OLED_Clear(); OLED_ShowString(0, 0, "Elder Guardian"); OLED_ShowString(0, 2, "Initializing..."); OLED_Refresh(); // 等待网络连接成功 while(WiFi_Status != WIFI_CONNECTED) { HAL_Delay(500); } OLED_ShowString(0, 2, "WiFi Connected "); OLED_Refresh(); HAL_Delay(1000); OLED_Clear(); while (1) { // 1. 读取传感器数据 (每2秒一次) static uint32_t last_sensor_time = 0; if(HAL_GetTick() - last_sensor_time > 2000) { last_sensor_time = HAL_GetTick(); if(DHT11_Read_Data(&temperature, &humidity)) { // 更新OLED显示 OLED_ShowString(0, 0, "Temp:"); OLED_ShowNum(40, 0, temperature, 2); OLED_ShowString(60, 0, "C Hum:"); OLED_ShowNum(90, 0, humidity, 2); OLED_ShowString(114, 0, "%"); } motion_detected = HAL_GPIO_ReadPin(PIR_GPIO_Port, PIR_Pin); if(motion_detected) { last_motion_time = HAL_GetTick(); // 更新最后活动时间 OLED_ShowString(0, 2, "Motion: Yes "); } else { OLED_ShowString(0, 2, "Motion: No "); } OLED_Refresh(); } // 2. 检查无活动超时报警 (逻辑判断) if((HAL_GetTick() - last_motion_time > MOTION_TIMEOUT) && (last_motion_time != 0)) { // 触发无活动报警 Send_Alert_To_Cloud("NO_MOTION_TIMEOUT"); last_motion_time = HAL_GetTick(); // 重置,避免连续报警 OLED_ShowString(0, 4, "Alert:No Motion!"); OLED_Refresh(); } // 3. 定时上传数据到云端 if(HAL_GetTick() - last_upload_time > UPLOAD_INTERVAL) { last_upload_time = HAL_GetTick(); Upload_Sensor_Data_To_Cloud(temperature, humidity, motion_detected); OLED_ShowString(0, 6, "Data Uploaded "); OLED_Refresh(); } // 4. 处理ESP8266接收到的数据 (在串口中断中填充缓冲区,这里解析) ESP8266_DataProcess(); HAL_Delay(100); // 主循环延时,降低CPU占用 } } // 紧急按键中断服务函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == KEY_Pin) { // 消抖处理 HAL_Delay(50); if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_RESET) { // 发送紧急报警到云端 Send_Alert_To_Cloud("EMERGENCY_BUTTON"); OLED_ShowString(0, 4, "Alert:EMERGENCY!"); OLED_Refresh(); } } }

4.3 机智云接入与数据通信

机智云提供了完整的IoT接入方案。我们需要在开发者中心创建产品,定义数据点,然后按照其通信协议封装数据。

  1. 创建产品与数据点

    • 登录机智云开发者中心,创建新产品,如“独居老人监护器”。
    • 定义数据点(Data Points):
      • temperature(温度): 读写类型,数值范围0-50。
      • humidity(湿度): 读写类型,数值范围20-90。
      • motion(活动): 读写类型,布尔值(0/1)。
      • alert(报警): 只写类型,枚举值(0:正常,1:无活动超时,2:紧急按钮)。
    • 记录产品的Product KeyProduct Secret,以及每个数据点的标识名。
  2. 设备端协议对接

    • 机智云设备接入协议相对固定。我们需要根据产品的Product Key和设备MAC地址生成一个PK + MAC的校验码,作为设备唯一标识(did)。
    • 通信数据需要按照机智云的标准格式进行封装,通常包括包头、数据长度、命令、序列号、数据内容、校验和等。

示例数据上报函数(简化逻辑):

// 根据机智云文档实现的数据打包函数 void Gizwits_PacketSensorData(uint8_t *buf, uint8_t temp, uint8_t humi, uint8_t motion) { // 这里是伪代码,实际需按机智云《设备接入协议文档》拼接字节 buf[0] = 0xFF; // 包头 buf[1] = 0xFF; buf[2] = 0x03; // 命令: 数据上报 buf[3] = 0x00; // 数据长度高字节 buf[4] = 0x06; // 数据长度低字节 (假设6个字节数据) buf[5] = temp; // 温度数据 buf[6] = humi; // 湿度数据 buf[7] = motion; // 活动状态 // ... 计算校验和 buf[8] } void Upload_Sensor_Data_To_Cloud(uint8_t temp, uint8_t humi, uint8_t motion) { uint8_t send_buf[64]; uint16_t len; // 1. 按照协议打包传感器数据 len = Gizwits_PacketSensorData(send_buf, temp, humi, motion); // 2. 通过ESP8266发送 ESP8266_SendData(send_buf, len); }

报警上传函数类似,只是命令字和数据内容不同。

  1. APP端查看
    • 使用机智云提供的“机智云”APP或自定义开发APP,扫描设备二维码或手动添加设备,即可实时查看传感器数据和报警信息。

5. 常见问题与调试技巧

在开发过程中,你可能会遇到以下问题:

问题现象可能原因排查思路与解决方案
OLED屏幕不亮或乱码1. I2C地址错误。
2. I2C引脚接反或接触不良。
3. 初始化序列错误。
4. 电源电压不足。
1. 用逻辑分析仪或I2C扫描程序确认设备地址(0x78或0x7A)。
2. 检查SCL/SDA连接,确认上拉电阻(通常OLED模块已集成)。
3. 核对初始化命令,特别是对比度、显示开关命令。
4. 确保供电为3.3V且稳定。
DHT11读取总是失败1. 时序不精确。
2. 总线未加上拉电阻。
3. 传感器损坏或接触不良。
4. 延时函数不准确。
1.最重要:使用示波器或逻辑分析仪查看DATA线时序,确保起始信号、等待响应、位读取的时间满足手册要求。STM32的delay_us函数在72MHz下需要精细校准。
2. 在DATA线和VCC之间接一个4.7K-10K的上拉电阻。
3. 更换传感器测试。
4. 使用系统滴答定时器(HAL_Delay)实现微秒延时,或使用定时器精确延时。
ESP8266无响应或AT指令失败1. 波特率不匹配。
2. 供电不足。
3. 接线错误(TX/RX反接)。
4. 模块未进入AT模式(GPIO0需拉高)。
5. 固件问题。
1. 确认STM32串口与ESP8266波特率一致(通常115200)。先用USB转TTL连接电脑,用串口助手测试AT指令。
2.单独给ESP8266供电,或确保你的3.3V电源能提供至少500mA电流。这是最常见的问题!
3. 检查TX接RX,RX接TX。
4. 确保ESP-01S的GPIO0引脚在上电时处于高电平(悬空或接3.3V)。
5. 尝试重新烧录稳定的AT固件。
能连WiFi但连不上机智云服务器1. 网络问题(路由器限制)。
2. 产品密钥(PK/PS)错误。
3. 协议封装错误。
4. 服务器地址或端口错误。
1. 尝试用ESP8266连接其他网络服务(如AT+CIPSTART="TCP","www.baidu.com",80)测试外网连通性。
2. 仔细核对开发者中心的产品信息。
3.使用网络调试工具(如网络调试助手)模拟设备发送数据包,与协议文档逐字节比对,这是定位协议问题最高效的方法。
4. 确认使用的是正确的服务器地址和端口(m2m.gizwits.com, 80/8883)。
系统运行一段时间后死机1. 堆栈溢出。
2. 中断处理不当。
3. 看门狗未喂狗。
4. 电源不稳定。
1. 在Keil中调整启动文件的堆栈大小。检查是否有大型局部数组。
2. 确保中断服务函数(如串口接收中断)执行时间尽可能短,避免在中断内调用HAL_Delay等阻塞函数。
3. 如果开启了独立看门狗(IWDG),需定期喂狗。
4. 检查电源模块,尤其是当所有外设同时工作时电压是否被拉低。

通用调试建议:

  • 分模块调试: 务必先让每个模块(OLED、DHT11、ESP8266)单独工作,再整合。
  • 善用串口打印: 在关键步骤(如初始化成功、数据读取、指令发送)后,通过STM32的另一个串口(或重定向printf)打印日志,是嵌入式调试的利器。
  • 逻辑分析仪是神器: 对于I2C、单总线、UART通信问题,一个几十块的逻辑分析仪能直观显示波形和时序,事半功倍。

6. 优化扩展与最佳实践

一个基础系统完成后,可以考虑以下优化和扩展,使其更稳定、更实用:

  1. 低功耗设计

    • 对于电池供电场景,可以使用STM32的休眠模式。在无活动超时后,让STM32进入STOP模式,仅保留RTC和外部中断(如PIR或按键)唤醒。ESP8266也可以仅在需要上传数据时上电。
    • 调整传感器采样频率,非必要时不采集。
  2. 数据可靠性

    • 增加重发机制: 云端未回复ACK或网络异常时,将数据包存入缓冲区,定时重发,最多重试3-5次。
    • 本地存储: 加入SPI Flash或EEPROM,在网络中断时临时存储报警和重要数据,网络恢复后补传。
    • 数据滤波: 对DHT11的读数进行滑动平均滤波,避免显示值跳动剧烈。
  3. 功能扩展

    • 增加更多传感器: 如MQ-2烟雾传感器、蜂鸣器声光报警、DS1302时钟模块为OLED提供准确时间。
    • 本地语音提示: 加入SYN6288语音模块,在报警时用语音提醒老人(如果听力尚可)。
    • 电池电量监测: 使用ADC检测电池电压,电量低时上报云端提醒充电或更换电池。
    • OTA远程升级: 利用STM32的IAP功能和机智云平台,实现固件远程升级,修复bug或增加功能无需上门。
  4. 代码结构优化

    • 使用RTOS: 如果功能复杂,可以考虑移植FreeRTOS,将传感器采集、网络通信、显示刷新等任务拆分,提高系统响应性和可维护性。
    • 模块化编程: 将每个外设的驱动、业务逻辑、网络协议分层,方便代码复用和阅读。
    • 配置文件: 将WiFi SSID/密码、服务器地址、报警阈值等配置信息存储在Flash的固定区域,甚至可以通过串口或蓝牙在配网时修改。
  5. 生产注意事项

    • 静电防护: 所有IO口,尤其是外接传感器的引脚,建议串联电阻或增加TVS管进行保护。
    • 电源去耦: 在MCU和每个主要芯片的电源引脚附近放置0.1uF和10uF的电容,滤除高频和低频噪声。
    • 外壳与安全: 设计3D打印或购买合适的外壳,避免电路板裸露。确保紧急按键大而醒目,方便老人操作。

通过以上步骤,一个功能完备、稳定可靠的独居老人监护系统就搭建完成了。它不仅是一个STM32的学习项目,更是一个能解决实际问题的物联网应用。你可以在此基础上继续深化,比如设计更美观的PCB、开发更友好的手机APP界面,甚至尝试接入其他IoT平台。

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

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

立即咨询