基于STM32与物联网的智能监护系统:从传感器到云端的完整实现
最近在做一个社区关怀项目需要为独居老人设计一套低成本、易部署的居家监护方案。核心需求是能实时监测老人的活动状态并在异常时及时通知家人。经过一番选型最终决定基于STM32微控制器来搭建这套系统因为它兼具了性能、功耗和丰富的生态支持。本文将完整分享从硬件选型、软件设计到云端联调的全过程手把手教你打造一个功能完整的“基于STM32的独居老人监护系统”。无论你是嵌入式新手想练手还是正在寻找实际项目方案的开发者都能从中获得可直接复用的代码和配置。1. 系统背景与核心设计思路随着社会老龄化加剧独居老人的安全与健康监护成为一个日益突出的社会问题。传统的定期上门探望或电话问候存在时间盲区无法做到24小时不间断的守护。因此利用物联网技术构建智能监护系统实现非侵入式的实时监测与预警具有重要的现实意义。本系统的核心设计目标是低成本、低功耗、易用、可靠。我们选择STM32F103C8T6俗称“蓝桥杯”或“最小系统板”作为主控它价格低廉、资源丰富足以胜任本项目的需求。系统通过多种传感器采集环境与人体活动数据经由WiFi模块上传至云端平台如机智云家属可通过手机APP远程查看状态并接收报警信息。系统核心功能模块包括环境监测使用DHT11温湿度传感器监测室内环境。活动感知使用HC-SR501人体红外传感器PIR监测老人是否在活动区域出现。紧急呼叫设置一个物理按键供老人在紧急情况下主动触发报警。本地显示使用0.96寸OLED显示屏SSD1306驱动实时显示传感器数据、系统状态和时间。无线通信使用ESP8266 WiFi模块AT指令固件连接家庭路由器将数据上传至云端。云端与远程通知数据上传至机智云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、电阻等-用于连接与调试核心连接示意图基于STM32F103C8T6ESP8266 (ESP-01S):VCC- 3.3V (注意必须接3.3V!)GND- GNDTX- STM32的PA3(USART2_RX)RX- STM32的PA2(USART2_TX)CH_PD- 3.3VGPIO0- 悬空或接高电平运行模式OLED (I2C):VCC- 3.3VGND- GNDSCL- STM32的PB6(I2C1_SCL)SDA- STM32的PB7(I2C1_SDA)DHT11:VCC- 3.3VGND- GNDDATA- STM32的PA1(GPIO)HC-SR501:VCC- 5V (该模块通常需要5V供电)GND- GNDOUT- STM32的PA0(GPIO)紧急按键:一端接GND另一端接STM32的PA8(GPIO)并在PA8与3.3V之间接一个10K上拉电阻。2.2 软件开发环境IDE/工具链Keil uVision5 (MDK-ARM) 主流的STM32开发IDE。确保已安装对应STM32F1系列的Device Family Pack。STM32CubeMX强烈推荐使用。用于图形化配置引脚、时钟、外设并生成初始化代码框架能极大提高开发效率避免底层配置错误。串口调试助手 如XCOM、SSCOM用于调试ESP8266的AT指令和查看系统打印日志。机智云开发者中心 用于创建产品、定义数据点、获取设备通信密钥。固件库HAL库 本项目使用STM32CubeMX生成的HAL库代码。HAL库抽象程度高可移植性好适合快速开发。OLED/传感器驱动 需要准备或编写SSD1306 OLED的I2C驱动、DHT11的单总线驱动。版本说明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); // 更新显存到屏幕初始化流程配置STM32的I2C1PB6, PB7为标准模式速度100kHz或400kHz。向OLED发送一系列初始化命令序列可在商家例程中找到设置对比度、扫描方式、开启显示等。在STM32内部维护一个OLED_GRAM[128][8]的显存数组所有绘图操作先修改这个数组。调用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(j0; j5; j) { for(i0; i8; 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指令流程测试通信AT- 回复OK设置模式ATCWMODE1- 设置为Station模式连接路由器连接WiFiATCWJAP你的WiFi名,你的WiFi密码- 回复WIFI CONNECTED和WIFI GOT IP连接机智云服务器ATCIPSTARTTCP,m2m.gizwits.com,80(或ATCIPSTARTSSL,m2m.gizwits.com,8883用于加密)发送数据ATCIPSEND长度- 收到后发送具体的协议数据。我们需要在STM32上实现一个稳定的AT指令发送与解析函数。关键点在于处理串口接收中断使用状态机解析OK、ERROR以及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生成工程框架打开STM32CubeMX选择MCU型号STM32F103C8Tx。配置时钟 在RCC中将HSE设置为Crystal/Ceramic Resonator。在Clock Configuration标签页将系统时钟源设置为HSE并将主频设置为72MHzSTM32F103的最高频率。配置GPIOPA1: 输出模式初始化时用于控制DHT11总线。PA0: 输入模式用于读取HC-SR501。PA8: 外部中断模式下降沿触发按键按下接地用于紧急呼叫。配置I2C1 模式选择I2C保持默认设置。配置USART2 异步模式波特率115200与ESP8266默认一致。配置SYS Debug选择Serial Wire如果要用ST-Link调试。生成代码 设置好工程路径、名称、选择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接入方案。我们需要在开发者中心创建产品定义数据点然后按照其通信协议封装数据。创建产品与数据点登录机智云开发者中心创建新产品如“独居老人监护器”。定义数据点Data Pointstemperature(温度): 读写类型数值范围0-50。humidity(湿度): 读写类型数值范围20-90。motion(活动): 读写类型布尔值0/1。alert(报警): 只写类型枚举值0:正常1:无活动超时2:紧急按钮。记录产品的Product Key和Product Secret以及每个数据点的标识名。设备端协议对接机智云设备接入协议相对固定。我们需要根据产品的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); }报警上传函数类似只是命令字和数据内容不同。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接RXRX接TX。4. 确保ESP-01S的GPIO0引脚在上电时处于高电平悬空或接3.3V。5. 尝试重新烧录稳定的AT固件。能连WiFi但连不上机智云服务器1. 网络问题路由器限制。2. 产品密钥PK/PS错误。3. 协议封装错误。4. 服务器地址或端口错误。1. 尝试用ESP8266连接其他网络服务如ATCIPSTARTTCP,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. 优化扩展与最佳实践一个基础系统完成后可以考虑以下优化和扩展使其更稳定、更实用低功耗设计对于电池供电场景可以使用STM32的休眠模式。在无活动超时后让STM32进入STOP模式仅保留RTC和外部中断如PIR或按键唤醒。ESP8266也可以仅在需要上传数据时上电。调整传感器采样频率非必要时不采集。数据可靠性增加重发机制 云端未回复ACK或网络异常时将数据包存入缓冲区定时重发最多重试3-5次。本地存储 加入SPI Flash或EEPROM在网络中断时临时存储报警和重要数据网络恢复后补传。数据滤波 对DHT11的读数进行滑动平均滤波避免显示值跳动剧烈。功能扩展增加更多传感器 如MQ-2烟雾传感器、蜂鸣器声光报警、DS1302时钟模块为OLED提供准确时间。本地语音提示 加入SYN6288语音模块在报警时用语音提醒老人如果听力尚可。电池电量监测 使用ADC检测电池电压电量低时上报云端提醒充电或更换电池。OTA远程升级 利用STM32的IAP功能和机智云平台实现固件远程升级修复bug或增加功能无需上门。代码结构优化使用RTOS 如果功能复杂可以考虑移植FreeRTOS将传感器采集、网络通信、显示刷新等任务拆分提高系统响应性和可维护性。模块化编程 将每个外设的驱动、业务逻辑、网络协议分层方便代码复用和阅读。配置文件 将WiFi SSID/密码、服务器地址、报警阈值等配置信息存储在Flash的固定区域甚至可以通过串口或蓝牙在配网时修改。生产注意事项静电防护 所有IO口尤其是外接传感器的引脚建议串联电阻或增加TVS管进行保护。电源去耦 在MCU和每个主要芯片的电源引脚附近放置0.1uF和10uF的电容滤除高频和低频噪声。外壳与安全 设计3D打印或购买合适的外壳避免电路板裸露。确保紧急按键大而醒目方便老人操作。通过以上步骤一个功能完备、稳定可靠的独居老人监护系统就搭建完成了。它不仅是一个STM32的学习项目更是一个能解决实际问题的物联网应用。你可以在此基础上继续深化比如设计更美观的PCB、开发更友好的手机APP界面甚至尝试接入其他IoT平台。