
简介本资源是一套基于STM32F1系列微控制器与ESP8266 Wi-Fi模块的智能婴儿床嵌入式开发完整工程面向嵌入式初学者、物联网课程设计者及智能家居项目开发者解决婴儿睡眠环境实时监测与远程智能控制的实际需求。压缩包含404个文件总计52.59MB涵盖54个C源文件核心驱动与业务逻辑、57个头文件h与58个编译中间文件o/d以及Java端App代码15个、MQTT/OneNet云平台对接模块onenet.__i、mqttkit.__i等、传感器驱动sg90.__i、relay.__i、cjson.__i和Keil工程配置uvprojx/uvoptx结构清晰便于分层理解硬件驱动、通信协议与云端交互。已有29人学习下载资源提供可直接编译烧录的HEX固件、完整传感器融合算法实现温湿度、红外翻身、压力防跌落、手机App控制逻辑及异常报警触发机制是深入掌握STM32ESP8266协同开发、IoT设备端到云全链路实践的典型教学案例。1. 项目缘起从“睡渣”宝宝到智能守护作为一名嵌入式开发者同时也是新手奶爸我深刻体会过半夜无数次惊醒、蹑手蹑脚去摸宝宝鼻息、反复确认被子是否盖好的焦虑。市面上的智能婴儿床要么价格昂贵功能花哨不实用要么数据封闭无法满足我自定义监控和远程查看的需求。于是一个念头自然产生为什么不自己动手用最熟悉的STM32和ESP8266打造一个完全符合自己需求的智能婴儿床监测与控制系统呢这个项目的核心目标很明确低成本、高可靠、可扩展。我们需要实时监测婴儿床内的关键环境数据如温湿度并能通过手机远程查看同时最好能集成一些主动干预功能比如在温度过高时自动开启小风扇或者当监测到异常哭闹时通过手机提醒。STM32作为主控负责精准的数据采集和设备控制ESP8266则担当联网重任将数据上传至云端并接收来自手机App的指令。整个系统就像一个24小时在线的“电子保姆”让父母能更安心地获得片刻休息。接下来我将详细拆解这个项目的完整实现过程从硬件选型到软件架构再到具体的代码实现与调试心得。2. 硬件系统设计与核心器件选型一套稳定可靠的硬件是项目的基石。我的设计思路是模块化将传感、控制、通信、人机交互等功能分解到不同的模块上由STM32主控进行统一调度。2.1 主控单元STM32F103C8T6 “核心板”我选择了经典的“蓝桥杯”核心板其主控是STM32F103C8T6。选择它基于以下几点考虑性价比极高作为STM32F1系列的入门型号它价格亲民资源对于本项目绰绰有余。资源充足拥有64KB Flash、20KB RAM足够运行一个包含多个传感器驱动、通信协议和简单逻辑的操作系统如FreeRTOS或裸机程序。多达37个GPIO、3个USART、2个I2C、2个SPI接口为连接各种外设提供了极大便利。生态完善无论是标准库还是HAL库资料和社区支持都非常丰富开发过程中遇到问题很容易找到解决方案。注意STM32F103C8T6有多个版本如“C8”和“CB”其Flash容量可能不同。购买核心板时最好确认其具体型号并使用ST-Link Utility或CubeProgrammer连接后读取芯片ID进行验证避免后续程序烧写时出现容量不足的报错。2.2 网络连接模块ESP-01S WiFi模块ESP8266系列中ESP-01S以其小巧的尺寸和极低的功耗成为首选。它通过串口UART与STM32通信承担了所有的网络任务。工作模式我们让ESP-01S工作在Station模式连接家庭WiFi路由器。STM32通过AT指令集与它交互例如发送“ATCIPSTART”建立TCP连接或者“ATCIPSEND”发送数据。供电与电平ESP-01S的工作电压是3.3V且其GPIO也是3.3V电平。STM32F103C8T6的IO口虽然可以容忍5V输入但输出高电平约为3.3V因此两者可以直接连接。关键点在于ESP8266在发射WiFi信号时瞬时电流可能超过200mA必须确保供电线路的承载能力。我单独使用了一个AMS1117-3.3V稳压芯片为其供电并在电源引脚就近放置了100μF和0.1μF的电容进行退耦防止电压跌落导致模块重启。2.3 环境感知模块DHT11温湿度传感器与声音传感器DHT11温湿度传感器这是一款经典的复合数字传感器通过单总线协议与MCU通信。它提供了基本的温湿度数据精度对于婴儿房环境监测温度±2°C湿度±5%RH完全足够。其优点是接口简单、成本低。我将它放置在婴儿床的围栏内侧避免被阳光直射或空调出风口直吹以获取更贴近宝宝体感的环境数据。声音传感器模块这里我选用了一款模拟输出的声音传感器如KY-038。它本质上是一个高灵敏度的驻极体话筒加一级放大电路输出一个随环境声音强度变化的模拟电压。STM32通过ADC通道读取这个电压值。通过软件设置一个阈值当ADC值持续一段时间超过阈值时即可判断为“异常哭闹”或“持续噪音”。调试心得这个阈值需要在实际环境中校准。白天环境噪音大阈值要设高一些夜晚安静阈值可以设低。我最终在程序里实现了“学习模式”上电后头30秒采样环境底噪并以此动态计算阈值大大提高了适应性。2.4 执行与反馈模块继电器、风扇与OLED显示屏继电器模块用于控制强电设备如一个小型的USB风扇或加湿器。STM32通过一个GPIO口控制继电器的通断。重要安全提醒继电器模块的输入侧控制端与输出侧负载端是电气隔离的。接线时务必区分清楚将负载风扇的火线串联进继电器的常开触点零线直连。整个强电部分必须做好绝缘并放置在婴儿绝对无法触碰的位置。直流风扇选用5V USB供电的静音风扇由继电器控制通断。当DHT11检测到温度超过设定上限例如28°C时STM32驱动继电器闭合开启风扇通风降温。OLED显示屏SSD1306我选用了一款0.96英寸的I2C接口OLED屏用于本地显示当前温湿度、网络状态和控制模式。这对于现场调试和状态查看非常方便无需每次都打开手机App。I2C通信仅需两根线SCL SDA节省了宝贵的GPIO资源。2.5 系统供电与电路连接整个系统采用5V/2A的USB电源适配器供电。5V电源一路给继电器模块和USB风扇另一路通过AMS1117-3.3V稳压芯片转换为3.3V为STM32核心板、ESP-01S、DHT11、声音传感器和OLED屏供电。所有模块的GND必须共地。 连接示意图如下文字描述STM32 USART2 (PA2-TX, PA3-RX) - ESP-01S (RX, TX)STM32 PB6 (SCL), PB7 (SDA) - OLED (SCL, SDA)STM32 PA1 (ADC) - 声音传感器 AOSTM32 PB0 (GPIO) - DHT11 DATASTM32 PB5 (GPIO) - 继电器 INSTM32 3.3V, GND - 各模块电源3. 软件架构设计与通信协议软件部分采用“前后台”系统结合有限状态机的设计思想以保证程序的实时性和可维护性。没有引入RTOS以降低复杂性。3.1 主程序流程与状态机主循环main loop是一个超级循环依次调用各个模块的轮询函数。核心是一个控制状态机定义了系统的工作模式例如初始化模式、本地监控模式、联网模式、报警模式等。// 伪代码示例 typedef enum { SYS_MODE_INIT, SYS_MODE_LOCAL, // 仅本地显示不联网 SYS_MODE_ONLINE, // 正常联网上报 SYS_MODE_ALARM, // 触发报警哭闹/温湿度超限 SYS_MODE_CONFIG // WiFi配网模式通过按键触发 } SystemMode_t; int main(void) { // 硬件初始化 HAL_Init(); SystemClock_Config(); UART_Init(); // 用于调试和ESP8266通信 I2C_Init(); // OLED ADC_Init(); // 声音传感器 GPIO_Init(); // DHT11, 继电器控制 OLED_ShowWelcome(); // 显示启动画面 // 连接WiFi读取Flash中存储的SSID/密码或进入配网模式 if(ESP8266_ConnectWiFi() ! SUCCESS) { Enter_ConfigMode(); // 启动SmartConfig或网页配网 } SystemMode_t currentMode SYS_MODE_INIT; uint32_t sensorTick 0; uint32_t uploadTick 0; while (1) { // 1. 状态机处理 switch(currentMode) { case SYS_MODE_ONLINE: // 定时读取传感器每2秒 if(HAL_GetTick() - sensorTick 2000) { Read_DHT11(temp, humi); Read_SoundSensor(adcValue); sensorTick HAL_GetTick(); // 本地显示更新 OLED_DisplayData(temp, humi, adcValue); // 逻辑判断 if(temp TEMP_THRESHOLD) Relay_Ctrl(FAN, ON); if(adcValue SOUND_THRESHOLD) currentMode SYS_MODE_ALARM; } // 定时上传数据每10秒 if(HAL_GetTick() - uploadTick 10000) { Upload_To_Cloud(temp, humi, adcValue); uploadTick HAL_GetTick(); } // 检查网络心跳处理服务器下发的控制指令 ESP8266_Process(); break; case SYS_MODE_ALARM: // 闪烁OLED控制继电器报警如点亮一个警示灯并通过ESP8266发送紧急推送 Send_Alert_Message(“Sound Alert!”); // 报警持续一段时间后若恢复平静则返回ONLINE模式 if(Check_Alert_Clear()) currentMode SYS_MODE_ONLINE; break; // ... 其他模式处理 } // 2. 处理串口接收到的AT指令响应或服务器数据 UART_RxHandler(); // 3. 处理按键事件模式切换、配网触发等 Key_ScanHandler(); } }3.2 STM32与ESP8266的AT指令交互这是项目的通信核心。我编写了一个esp8266.c/.h文件来封装所有AT指令操作。关键在于可靠地解析ESP8266返回的数据。初始化与连接上电后STM32会发送AT、ATCWMODE1Station模式、ATCWJAPSSID,PASSWORD等指令并等待OK或ERROR的回应。这里必须加入超时重试机制。我通常设置最多重试5次每次失败后延时2秒。建立TCP连接连接到指定的云服务器或本地搭建的MQTT服务器。指令如ATCIPSTARTTCP,your_server.com,1883。对于MQTT后续还需要发送连接协议包这部分数据需要通过ATCIPSEND指令来发送。数据发送将传感器数据封装成JSON格式例如{temp:26.5, humi:60, sound:320}。通过ATCIPSENDlength告知ESP8266要发送的数据长度然后紧接着发送数据本体。数据接收ESP8266收到服务器数据或指令时会通过串口以IPD,len:data的格式主动上报。STM32的串口中断服务函数需要持续接收数据并放入一个环形缓冲区。主循环中的UART_RxHandler()函数再从缓冲区中解析出完整的IPD报文提取出data部分可能是服务器下发的控制指令如{fan:1}并执行相应动作。踩坑实录ESP8266的AT指令响应末尾有时是\r\n有时是\r\n\r\n。如果使用strstr()函数查找OK可能会因为换行符问题而失败。我的做法是在接收缓冲区中将\r和\n都替换为字符串结束符\0然后再进行查找匹配稳定性大大提升。3.3 云端数据交互方案选择我对比了两种主流方案私有TCP/UDP服务器和公共MQTT物联网平台。方案A自建TCP服务器。在公网云服务器如腾讯云轻量应用服务器上用Python的socket库写一个简单的TCP服务。STM32将JSON数据打包发送至此服务器端口服务器解析后存入数据库如SQLite并提供一个简单的Web页面进行数据展示。优点是数据完全私有可控性强。缺点是需要自己维护服务器处理网络稳定性、数据安全等问题开发量稍大。方案B使用公共MQTT平台。如阿里云物联网平台、OneNET、巴法云等。它们提供了设备接入、数据存储、规则引擎和App开发支持的一站式服务。ESP8266可以直接接入这些平台。我最终选择了巴法云原因如下对个人开发者免费额度足够本项目使用。接入极其简单提供了详细的ESP8266 AT指令接入示例。支持微信小程序和App通知可以直接将报警信息推送到手机微信无需自己开发App。支持主题订阅/发布非常适合“控制指令下发”这个场景。我在巴法云为设备创建了两个主题BabyBed/Data用于上传数据BabyBed/Ctrl用于接收手机App下发的控制指令如手动开关风扇。STM32订阅Ctrl主题当手机App发布一条{“fan”: 1}的消息到该主题时ESP8266会收到并转发给STM32执行。采用方案B让我在短时间内就实现了完整的“感知-上传-显示-控制”闭环可以将精力更集中在硬件和嵌入式逻辑本身。4. 关键功能实现与代码剖析4.1 DHT11单总线协议驱动DHT11的通信时序要求比较严格必须用微秒级延时。由于STM32的HAL库的HAL_Delay()是毫秒级的因此需要自己实现一个微秒延时函数通常用SysTick定时器或空循环实现。// 微秒延时函数基于SysTick需根据系统主频调整 void DHT11_Delay_us(uint16_t us) { uint32_t ticks us * (SystemCoreClock / 1000000) / 8; // 粗略计算 uint32_t start_tick SysTick-VAL; while ((start_tick - SysTick-VAL) ticks); } // 读取DHT11数据 uint8_t DHT11_Read_Data(float *temperature, float *humidity) { uint8_t data[5] {0}; uint8_t i, j; // 主机发起开始信号拉低至少18ms然后拉高20-40us HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET); DHT11_Delay_us(18000); // 18ms HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET); DHT11_Delay_us(30); // 30us // 设置引脚为输入等待DHT11响应 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DHT11_Pin; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(DHT11_GPIO_Port, GPIO_InitStruct); // 等待DHT11拉低80us while(HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET); while(HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET); // 等待低电平结束 while(HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET); // 等待高电平结束80us // 开始接收40位数据 for(i0; i5; i) { for(j0; j8; j) { // 等待每个位开始的50us低电平 while(HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET); // 测量高电平持续时间判断是026-28us还是170us uint32_t count 0; while(HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { count; DHT11_Delay_us(1); if(count 100) break; // 超时保护 } data[i] 1; if(count 40) { // 高电平时间长于40us认为是‘1’ data[i] | 0x01; } // 否则为‘0’不操作 } } // 校验和前4个字节之和的低8位应等于第5个字节 if(data[4] (data[0]data[1]data[2]data[3])) { *humidity (float)data[0] (float)data[1] / 10.0; *temperature (float)data[2] (float)data[3] / 10.0; return 1; // 成功 } return 0; // 失败 }调试心得DHT11对时序非常敏感不同主频的MCU需要调整DHT11_Delay_us函数的精度。最好的验证方法是使用逻辑分析仪抓取通信波形确保起始信号、位“0”、位“1”的时序符合数据手册要求。如果读取经常失败可以尝试在数据线DATA上加一个4.7K~10K的上拉电阻到VCC。4.2 基于ADC的声音阈值判断算法声音传感器的模拟值波动很大简单的单次阈值比较会产生大量误触发。我采用了一个“滑动窗口均值滤波持续超阈值计数”的算法。#define SOUND_SAMPLE_SIZE 10 // 滑动窗口大小 #define SOUND_ALARM_COUNT 5 // 连续超阈值次数 uint16_t sound_adc_buffer[SOUND_SAMPLE_SIZE] {0}; uint8_t buffer_index 0; uint8_t alarm_counter 0; uint16_t sound_threshold 500; // 初始阈值可通过学习模式调整 uint16_t Get_Sound_Level(void) { uint32_t sum 0; uint16_t avg; // 1. 采集新数据放入滑动窗口 sound_adc_buffer[buffer_index] HAL_ADC_GetValue(hadc1); buffer_index (buffer_index 1) % SOUND_SAMPLE_SIZE; // 2. 计算窗口内平均值 for(int i0; iSOUND_SAMPLE_SIZE; i) { sum sound_adc_buffer[i]; } avg sum / SOUND_SAMPLE_SIZE; // 3. 判断逻辑 if(avg sound_threshold) { alarm_counter; if(alarm_counter SOUND_ALARM_COUNT) { // 触发报警 return 2; // 报警状态 } } else { alarm_counter 0; // 安静则清零计数器 } return (avg sound_threshold) ? 1 : 0; // 1表示瞬时超阈值0表示正常 }这个算法有效过滤了突然的关门声、咳嗽声等短暂噪音只有当类似婴儿持续哭闹这种长时间超阈值的情况才会触发报警大大降低了误报率。4.3 OLED显示界面与状态可视化使用u8g2或ssd1306的驱动库可以方便地在OLED上绘制图形和文字。我设计了一个简单的两页界面通过短按按键切换。页面1主页面大字体显示当前温度和湿度底部小字显示声音ADC实时值和网络连接状态如“WiFi:OK”或“WiFi:Fail”。页面2设置/状态页显示声音报警阈值、风扇自动启停的温度阈值、设备ID等信息。在OLED_DisplayData函数中我不仅刷新数据还会根据状态改变显示元素。例如当系统处于报警模式时整个屏幕的边框会闪烁通过交替绘制和清空矩形框实现提供强烈的本地视觉警示。5. 系统集成、调试与优化心得将所有模块组装到一块洞洞板或定制PCB上后真正的挑战才开始。以下是几个关键的调试和优化环节。5.1 电源噪声与系统稳定性最初版本当继电器吸合或风扇启动时ESP8266会偶尔重启。用示波器观察3.3V电源线发现继电器动作瞬间有一个明显的电压毛刺。这是因为电机类感性负载在通断时会产生反向电动势干扰了同一电源网络。解决方案电源隔离为继电器模块和风扇单独提供一路5V电源与MCU及传感器的3.3V电源在输入端如USB口之后即分开。增加续流二极管在继电器线圈两端并联一个1N4007二极管阴极接电源正极吸收关断时产生的反向电动势。加强滤波在AMS1117的输入和输出端分别增加更大容量的电解电容如220μF和多个小容量陶瓷电容0.1μF, 0.01μF并联覆盖更宽的噪声频率。 经过这些改造后系统即使在频繁开关风扇的情况下也运行得非常稳定。5.2 AT指令通信的健壮性提升在实验室测试良好的代码放到实际家庭WiFi环境中可能会因为网络波动出现各种问题。我增强了ESP8266_SendCmd函数。指令应答匹配不仅等待OK对于像ATCIPSTART这样的指令还要等待CONNECT或ALREADY CONNECTED等特定响应。使用一个状态机来解析多行响应。超时与重试每个指令发送后设置一个合理的超时时间如3秒。如果超时未收到预期响应则重试。连续重试超过3次后执行“网络恢复流程”发送ATRST重启ESP8266模块然后重新连接WiFi和服务器。数据发送缓存设计一个发送缓存队列。当需要上传数据但当前网络连接不可用时将数据包暂存到队列中。待网络恢复后优先发送队列中的数据防止数据丢失。5.3 低功耗与续航考量电池供电方案虽然本项目主要使用市电但我也探索了电池供电的便携版本用于短时间外出监测如婴儿车。关键点在于让STM32和ESP8266在大部分时间进入休眠模式。STM32休眠使用STM32的Stop模式。在Stop模式下所有时钟停止SRAM和寄存器内容保持功耗可降至微安级。通过RTC定时唤醒例如每5分钟唤醒一次或外部中断唤醒如声音传感器触发。ESP8266电源管理通过一个MOS管电路由STM32的一个GPIO控制ESP8266的电源通断。仅在需要上传数据时STM32唤醒打开ESP8266电源等待其启动并连接网络发送数据然后立即断电。这比让ESP8266一直处于联网待机状态省电得多。传感器供电优化DHT11和声音传感器模块也由STM32的GPIO控制供电采样时才上电。 通过以上措施使用一块2000mAh的锂电池可以实现超过24小时的间歇性监测和数据上传每5分钟上传一次满足了临时外出使用的需求。5.4 数据安全与隐私保护即使使用第三方物联网平台也需要注意数据安全。MQTT TLS加密如果平台支持尽量使用MQTT over TLS端口8883进行连接避免数据明文传输。设备唯一标识与鉴权为每个设备生成唯一的Client ID和密码并在云平台注册。不在代码中硬编码敏感信息可以考虑在STM32的Flash中划出一块区域首次运行时通过配网流程将这些信息写入。控制指令校验在云端或手机App端对下发的控制指令如开关风扇进行身份和权限校验。在设备端也可以对收到的指令进行简单的格式或密码校验防止被恶意主题消息误触发。6. 项目扩展与未来展望这个基础框架具有很强的可扩展性。根据实际需求可以轻松添加更多模块睡眠质量监测在床垫下放置一个薄膜压力传感器阵列通过ADC多点采样分析宝宝的呼吸频率和体动情况。算法上可以通过FFT分析压力信号的周期性来判断呼吸。视频监控集成通过ESP32-CAM模块在触发声音报警后自动拍摄一张照片或一段短视频并通过MQTT推送到手机端让家长更直观地了解现场情况。环境光调节增加一个光敏电阻监测环境光照强度。当夜晚来临且检测到宝宝在床时自动调暗或关闭房间的主灯开启一个柔和的夜灯。本地语音提示接入一个SYN6288这类TTS语音合成模块当温度超限或风扇开启时用温和的语音进行本地播报适用于不习惯看手机App的家中老人。整个项目从构思到实现花费了大约两个周末的时间。最大的收获不是做出了一个多么酷炫的产品而是在解决一个个具体问题的过程中对STM32的外设驱动、状态机设计、串口通信协议解析、电源设计、EMC抗干扰等有了更深刻的理解。它完美地诠释了嵌入式开发的乐趣将想法通过代码和电路变成现实并切实地解决生活中的一个小痛点。希望这个详细的分享能为有兴趣的朋友提供一个清晰的实现路径和避坑指南。本文还有配套的精品资源点击获取