FEATURED · 精选文章

基于STM32和贝壳物联的智能家居系统设计与实现

发布时间 / 2026/8/29 8:55:04
来源 / 创域科博编辑部
栏目 / 资讯中心
基于STM32和贝壳物联的智能家居系统设计与实现 简介物联网IoT是嵌入式系统与网络技术结合的重要方向而智能家居则是其最具代表性的落地场景之一。在典型的物联网架构中MCU负责数据采集与设备控制WiFi模块负责网络通信云端平台实现远程管理与指令下发。STM32作为主流嵌入式微控制器凭借丰富的外设接口和成熟的HAL库生态成为众多开发者的首选。ESP8266则以其低成本、低功耗的串口转WiFi能力在物联网节点中广泛使用。通过贝壳物联平台提供的透明TCP通道设备可以轻松实现数据上报与远程控制整个交互过程清晰透明。该系统覆盖传感器驱动、串口通信、协议解析、TCP长连接管理等多个关键技术环节既适合毕设项目用于展示完整系统能力也适合工程实践用于理解物联网底层工作机理。本文从硬件选型、电路设计、STM32端软件架构到云端协议对接的完整链路展开为构建一个可用的智能家居环境监测与控制系统提供全面的参考方案。 很多人拿到“基于STM32的智能家居系统运用贝壳物联服务器”这个题目时第一反应是“又多了一个烂大街的毕设”。但说实话这个题目恰恰是嵌入式方向里少有的“麻雀虽小五脏俱全”的典型它把MCU裸机开发、外设驱动、串口通信、网络协议栈对接、物联网平台使用、移动端控制全部串在了一起。你把这个项目完整啃下来再去面嵌入式岗位聊项目经验时绝对有东西可讲而不是只会说“我做过一个温湿度采集”。这套系统的核心逻辑其实很简单STM32作为主控负责采集环境数据和驱动执行器ESP8266作为联网模块通过串口与STM32通信把数据上报到贝壳物联服务器手机端通过贝壳物联的App或网页就能实时查看数据、下发控制指令。整个过程涉及硬件接线、协议封包、TCP长连接管理、指令解析等多个环节每一个环节都有坑但也正是这些坑让这个项目值得做。我最初接触这个课题时也踩了不少弯路尤其是贝壳物联这个平台文档零散网上教程水平参差不齐很多是拿别人的代码改个名字就发出来。所以我花了一周多时间把整个链路重新梳理了一遍从硬件选型到云端对接全部自己验证过下面把完整方案和实操经验分享出来希望能帮你少走点弯路。1. 整体架构设计与核心思路拆解1.1 为什么选STM32和贝壳物联而不是其他组合在做方案选型时你可能会犹豫要不要用ESP32直接搞定或者用树莓派再或者用阿里云、腾讯云之类的平台我逐个分析一下你就明白这个组合的合理性了。先说主控。ESP32确实自带WiFi和蓝牙理论上一个芯片就能完成采集和联网开发也更快。但这是毕设/课程作业场景评委看重的是你对嵌入式底层原理的掌握程度。STM32需要你手动配置GPIO、ADC、USART、定时器需要你理解中断、DMA、时钟树这些恰恰是嵌入式面试的高频考点。ESP32的开发方式太偏向应用层很多底层细节被框架屏蔽了项目讲起来显得单薄。再说云平台。阿里云IoT、腾讯云IoT功能很强但封装程度太高SDK一拉设备接入、数据模板、规则引擎全都自动搞定你反而讲不清楚“设备到底是怎么跟服务器通信的”。贝壳物联的优势在于它够简单提供一个公网TCP接入地址你只要按照它的报文格式用串口或AT指令就能完成数据上报和指令接收整个协议交互过程是透明的。你就能真正看懂一条数据从MCU到云端再回到手机端中间每一层做了什么。最后说ESP8266。很多人问为什么不用STM32直接外接以太网模块。因为智能家居的部署环境一般没有网口WiFi才是现实选择。ESP8266在这个项目里的定位很纯粹一个串口转WiFi的透明通道。用AT指令就能驱动学习成本低而且它和STM32的串口通信逻辑清晰方便在答辩时画出明确的数据流图。1.2 数据流与系统分层整个系统的数据流可以拆成三条链路搞懂这三条链路你就理解了整个项目的骨血。第一条是传感器数据上行链路传感器比如DHT11、光敏电阻、烟雾传感器输出模拟或数字信号STM32通过ADC或GPIO读取原始值经过换算得到真实的温湿度、光照强度、烟雾浓度等数据然后通过串口以约定的帧格式发给ESP8266ESP8266再通过TCP协议把数据封装成贝壳物联要求的报文格式发送到服务器。第二条是控制指令下行链路手机App或网页端下发指令贝壳物联服务器把指令推送到ESP8266建立的TCP连接上ESP8266通过串口透传给STM32STM32解析指令帧后控制继电器、蜂鸣器、电机等执行器动作。第三条是心跳与状态维护链路TCP长连接如果长时间不通信会被服务端断开所以ESP8266需要定时发送心跳包维持连接。同时STM32也需要定期检查ESP8266的在线状态断线后自动重连。这三条链路不是独立运行的它们之间通过一个简单的状态机来调度。比如系统上电后先初始化外设然后AT指令配置ESP8266连WiFi、连服务器连接成功后再周期采集数据、发送数据同时实时监听串口接收到的指令。这里建议用前后台结构主循环处理采集上报串口中断缓冲接收指令不要用RTOS否则复杂度会陡增答辩时也不好讲。2. 硬件准备与电路设计细节2.1 硬件选型清单与理由我列一下实际用到的硬件清单这些都是比较常见的型号采购方便价格也便宜。模块型号建议作用注意事项主控STM32F103C8T6核心逻辑处理、传感器读取、指令解析性价比高资料多买最小系统板即可温湿度传感器DHT11采集环境温湿度也可以用DHT22精度更高但时序要求更严格光照传感器光敏电阻模块采集光照强度做智能灯光调节模块输出模拟量接STM32的ADC引脚烟雾/可燃气体MQ-2模块检测环境烟雾浓度触发报警上电后需要预热初期读数偏差大继电器模块单路/双路5V继电器控制灯光、风扇等220V设备必须与主控隔离用光耦继电器别共用电源WiFi模块ESP8266-01S串口转WiFi连接贝壳物联用3.3V供电注意电流峰值最好加电容显示模块OLED 0.96寸 I2C本地显示温湿度、系统状态I2C接口占用引脚少还能提升项目颜值蜂鸣器有源蜂鸣器烟雾报警、指令提示音有源的直接给电平就响无源的才需要PWM电源AMS1117-3.3 5V适配器给各模块稳定供电不要用电脑USB口直接带所有模块电流不够2.2 接线布局与关键防护很多新手在做这个项目时硬件部分最大的问题不是不会接线而是乱接线。乱接线的后果就是通信不稳定、数据跳变、模块烧毁。这里说几个关键点。第一个关键是电源隔离。ESP8266在工作时电流波动很大尤其是在WiFi发射瞬间峰值电流可以到300mA以上如果和STM32共用同一个LDO会造成电压跌落导致STM32复位。我实测过ESP8266发射瞬间如果供电能力不足STM32的3.3V纹波可以达到0.5V以上直接触发复位。解决办法是给ESP8266单独用一个AMS1117-3.3供电输入侧和STM32的5V分开走线再在ESP8266的VCC和GND之间并联一个100uF电解电容和一个0.1uF陶瓷电容。继电器模块一定要是光耦隔离版本否则继电器吸合瞬间的反向电动势和触点抖动会严重干扰ADC采样烟雾浓度数据会疯跳。第二个关键是串口电平匹配。STM32是3.3V逻辑电平ESP8266也是3.3V之间可以直接连接但要注意交叉接线STM32的TX接ESP8266的RXSTM32的RX接ESP8266的TXGND共地。很多新手在这步容易直接一一对应接结果通信全乱。另外如果你买的是ESP8266-01S它的GPIO0和GPIO2是烧录模式控制引脚正常运行时不要接上拉或下拉冲突的器件否则会出现连不上AT指令的情况。第三个关键是传感器布线与抗干扰。DHT11的数据线要尽量短最好控制在20cm以内否则时序容易出错读出来的温度永远是0或者传感器无响应。MQ-2模块的输出是模拟量信号线不要和继电器控制线平行走否则继电器切换时ADC采样值会出现尖峰。我在实际测试中就遇到过一次继电器吸合时MQ-2的ADC值直接从600跳到1023后来把线理清楚、加上滤波电容才解决。3. STM32端软件设计与核心代码实现3.1 工程搭建与CubeMX配置STM32端的开发我推荐用HAL库加CubeMX初始化虽然网上很多老教程还在用标准库但HAL库在代码维护性上更好而且CubeMX生成的初始化代码不容易遗漏外设配置。你不需要背太多寄存器操作把精力放在逻辑实现上。CubeMX里的关键配置项我先列出来RCCHSE外部晶振时钟树配置成72MHz主频。GPIODHT11数据引脚设为开漏输出模式光敏电阻模块的ADC引脚设为模拟输入继电器、蜂鸣器设为推挽输出按键设为上拉输入。ADC1开启两个通道光敏电阻、MQ-2扫描模式连续转换由DMA搬运结果。这里建议用DMA因为如果直接在循环里调用HAL_ADC_Start_IT每采集一路都要等待转换完成整条系统的时间片就被占住了后面做串口接收解析时容易丢帧。USART1连接ESP8266配置为115200波特率、8位数据位、1位停止位、无校验开启接收中断。USART2可选作为调试串口连接电脑方便打印日志。我在开发过程中靠这个串口救了无数次命。比如想确认DHT11读出来到底是多少或者ESP8266返回的AT指令结果是什么直接在USART2打出来一目了然。I2C1OLED显示屏用默认配置即可。TIM41ms定时器作为系统时基用来做非阻塞延时、心跳包计时、超时判断。3.2 传感器数据读取与处理DHT11的读取是这个项目里第一个容易卡住的地方。DHT11是单总线协议时序要求比较严格但又不是严格到必须用定时器输入捕获用GPIO模拟时序配合延时就能搞定。我在代码里用的是HAL库的HAL_GPIO_WritePin和HAL_Delay配合要注意的是HAL_Delay的精度只有1ms而DHT11的时序很多是微秒级的所以延时函数要用一个基于TIM4的delay_us来实现或者直接用DWT-CYCCNT做精确延时。这里有个细节如果直接用HAL_Delay(20)来发起始信号20ms的误差其实无所谓但读取响应信号和40个数据位时主机需要在40-80us的窗口内完成采样用delay_us都是必须的。代码流程是这样的主机拉低数据线保持18ms以上释放总线等待DHT11响应。DHT11拉低80us再拉高80us表示准备好发送数据。然后连续发送40位数据每一位都以50us低电平开头如果是“0”高电平持续26-28us如果是“1”高电平持续70us左右。主机读取时先等数据线变为高电平然后延时40us再读引脚电平。如果读到高电平说明这一位是“1”否则是“0”。因为DHT11每次读取后需要间隔至少1秒我在主循环里的采集周期就设置为2秒一次避免连续读取导致的数据异常。ADC部分就简单很多。光敏电阻模块输出的模拟电压和光照强度成反比MQ-2模块的模拟输出电压和气体浓度成正比。CubeMX里已经把DMA配置好了我只需要在初始化后调用一次HAL_ADC_Start_DMA然后从DMA缓冲区里读取两个通道的原始值。注意DMA缓冲区的数据类型是uint32_t还是uint16_t要和CubeMX里配置的ADC数据宽度一致否则读出来全是0。原始ADC值需要换算成实际物理量。光照强度我不做精确的照度换算只做分档处理比如ADC值大于3000判定为“暗”在1000-3000之间是“正常”小于1000是“亮”。这样既简单又够用。烟雾浓度则直接上报原始ADC值由云端或手机端来判断是否报警阈值设在500左右超过就触发蜂鸣器报警。3.3 STM32与ESP8266的串口通信协议STM32和ESP8266之间的通信不是直接把传感器数据扔给ESP8266就完事了。因为ESP8266那边要负责TCP连接、心跳维护、数据上报它需要知道每一帧数据的边界在哪里。所以我在串口通信上自定义了一个简单的帧协议结构如下帧头(0xAA) 数据长度(1字节) 数据域(N字节) 校验和(1字节)数据域里再细分字段比如温度、湿度、光照、烟雾、设备状态等用固定位置存放这样解析简单不会出错。举个例子上报数据帧的内容可能是AA 08 14 1E 05 DC 02 00 00 35其中0xAA是帧头0x08是长度不含帧头长度和校验和0x14是温度十六进制20即20度0x1E是湿度十六进制30即30%0x05 0xDC是光照ADC值低字节在前0x02是烟雾浓度等级0x00是继电器1状态0x00是继电器2状态最后0x35是前面所有字节的累加和。在STM32端我用串口空闲中断加DMA接收或者用接收中断加状态机解析。我实际用的是后者因为ESP8266返回的AT指令结果和云端下发的指令是混在一起的用状态机逐字节解析最灵活。核心逻辑是收到一个字节就进入状态机判断当前状态是找帧头、读长度、收数据还是校验校验通过后再根据帧类型分发处理。ESP8266端的AT指令配置我也写清楚ATCWMODE1 // 设置为Station模式 ATRST // 重启模块生效 ATCWJAP你的WiFi名,你的WiFi密码 // 连接家庭WiFi ATCIPSTARTTCP,www.bigiot.net,8181 // 连接贝壳物联服务器 ATCIPMODE1 // 进入透传模式这里有个坑贝壳物联服务器的TCP端口是8181不是默认的80。这个端口信息在贝壳物联官网的“设备接入”文档里写得不太显眼很多教程里就直接跳过了导致很多人连不上服务器。另外ATCIPMODE1开启透传模式后所有从串口发出的数据都会直接转发到TCP连接上反过来说服务器推送的数据也会从串口直接输出。这个模式配置成功后ESP8266会返回OK之后就不会再显示SEND OK之类的内容了所有串口收到的数据要么是你自己发的回显要么是云端的指令。在线透传模式下ESP8266有一个严重的坑模块会实时转发服务器下发数据但是如果你的STM32还在串口中断里做耗时操作或者主循环里有较长延时就会把后面的数据包冲掉。所以我在主循环里把所有阻塞式的延时全部改成了非阻塞方式用TIM4的1ms标志位来计时绝不在中断里调用HAL_Delay。4. 贝壳物联平台接入与协议对接4.1 服务器侧配置与设备创建贝壳物联bigiot.net这个平台本质上是一个物联网数据中转服务它提供免费的设备接入能力设备通过TCP加密连接明文端口8181加密端口需要额外处理SSL与服务器通信使用JSON格式报文。使用之前你需要先注册一个账号在控制台里创建两个对象一个是设备Device一个是应用Application。关键信息有三个设备IDdevice_id、API Keyapi_key、应用ID。设备ID和API Key是你控制设备的凭证本质上就是一个“用户名和密码”。应用ID是用来和手机App绑定的你在贝壳物联的App里登录同一个账号绑定你的应用就能看到设备列表。这三个参数在代码里要作为常量存好后面所有JSON报文里都会用到。创建完设备后设备默认是离线状态。当ESP8266通过TCP协议连上8181端口并发送第一条认证报文后设备才会变在线。设备如果长时间不发送心跳平台会判定设备离线这个离线超时时间在平台端大概是几十秒到几分钟不等所以心跳间隔建议设成30秒一次不要设太频繁太频繁会被限流太慢会被判离线。4.2 认证、心跳、数据上报与指令接收的报文格式贝壳物联的报文格式是基于JSON的这是整个项目对接过程中最需要仔细理解的部分。每一步报文我都在项目里验证过格式如下认证报文连接后立即发送{M:checkin,ID:设备ID,K:设备API Key}这个报文的作用是告诉服务器“我是谁”。如果认证成功设备状态会变为在线而且服务器会返回一条确认消息ESP8266会从串口打出来。很多教程没说这一步导致数据一直上报不上去就是因为少了认证。心跳报文每30秒发送一次{M:checkin,ID:设备ID,K:设备API Key}没错心跳报文和认证报文格式一样。这也是贝壳物联一个很别致的设计你不需要额外的“心跳”指令只要间隔时间内发送一次checkin报文服务器就知道设备还活着。数据上报报文{M:update,ID:设备ID,V:{温度:26,湿度:58}}注意V字段是一个JSON对象里面的key是你在设备里定义的“数据点”名称value是字符串类型的数值。数据点名称在平台创建设备时就要定义好比如“温度”“湿度”“光照”“烟雾”等。这里有个关键点数据点名称是大小写敏感的而且value必须是字符串不能直接传数字否则服务器解析会失败。控制指令接收当你在App端点击一个按钮服务器会把指令推送给设备的TCP连接。指令报文格式如下{M:cmd,ID:设备ID,C:{指令点名称:指令值}}比如你定义了一个指令点叫“LED”在App里按下“开”服务器就会推送{M:cmd,ID:123,C:{LED : 开}}。STM32解析到C字段之后再提取指令点名称和值映射到对应的GPIO操作上。实际测试中我还发现一个细节贝壳物联的App界面里打开设备详情页后你定义的“数据点”会以卡片形式展示点击卡片可以切换指令。但这个界面做得很隐蔽很多人找不到从哪里继控制设备。其实逻辑是在App首页找到你的设备点进去最下方有个“数据点”区域点数据点对应的卡片会弹出控制选项。这个操作路径如果答不出来答辩时现场翻找会很尴尬。4.3 数据上报间隔与流量控制关于数据上报频率我之前遇到过一个问题把上报间隔设成1秒结果搞了半小时服务器就不再接收我的数据了设备状态变成在线但数据不再更新。后来排查发现贝壳物联对免费用户的请求频率有限制1秒一次太频繁触发了限流。正常按2-5秒上报一次就非常稳。我在最终版本里设置的采集和上报周期是3秒30秒发一次心跳这样既能保证数据实时性又不会触发限流。另外千万注意ESP8266在透传模式下的一个特性每次发送数据前模块会先连续发送几个字节的提示符然后才转入数据发送数据发送完后模块会在后面追加一个回车换行。所以在STM32代码里组帧后可以一次性把整包JSON报文通过串口发出去不需要关心模块内部怎么处理但发送长度不要超过TCP缓冲区一般是1460字节我们这种几十字节的小报文远远够用。5. 系统联调与常见问题排查5.1 分模块调试法别等全部写完再联调我踩过最大的一个坑就是把所有模块写完后才整体联调结果出了问题根本不知道是STM32、ESP8266还是服务器哪一环出了问题。后来我总结了分模块调试法强烈建议你也按这个顺序来。第一步先单测STM32。把传感器采集的逻辑单独跑一遍通过USART2打印到电脑串口助手确认温度、湿度、光照、烟雾的数据都正常。比如DHT11读出来是Temp26.5C Humi58.2%ADC读出来是稳定值说明传感器和主控没问题。这一步不需要接ESP8266完全离线调试。第二步单测ESP8266。用一个USB转TTL模块把ESP8266直接接到电脑的串口助手用AT指令手动操作先连WiFi再连TCP服务器再手动发送认证报文、心跳报文然后在贝壳物联App上看设备是否在线、能否收到数据。这一步验证了整个网络链路和服务器配置没问题。我在这一步发现了一个很常见的问题WiFi连不上可能是模块供电问题TCP连接失败可能是端口写错或者WiFi信号弱这些问题在接上STM32之前先暴露后面就省心多了。第三步把STM32和ESP8266连起来联调。先用STM32发送一行简单的AT指令比如AT看ESP8266是否返回OK确认串口通信正常。然后逐步加复杂度发送ATCIPSTART连接服务器发认证报文再发数据上报报文。最后验证指令下发链路在App里点按钮看STM32能否从串口收到JSON报文并且正确解析。每走通一步就记录下来后续出问题直接定位到具体环节。5.2 高频问题速查表现象可能原因解决办法STM32发送AT无响应TX/RX接反或GND未共地检查交叉连接确保两端GND相连ESP8266连不上WiFi供电不足信号弱密码错误单独供电靠近路由器测试检查AT回显ESP8266返回ERRORAT指令格式错误模块未烧录正确固件手动串口助手逐条测试确认固件版本TCP连接不上8181端口写错或IP用成了域名但AT版本不支持确认端口为8181使用ATCIPSTART时试IP方式设备在线但收不到数据认证报文未发送或API Key错误确保连接后第一个报文是checkin认证数据点不显示数值JSON格式错误value不是字符串key名称不匹配用串口助手打印sent报文核对JSON格式和keyApp无法控制设备未绑定应用或指令点未定义在贝壳物联控制台绑定应用重新定义指令点继电器动作后ADC跳变电源干扰或信号线受干扰光耦隔离加滤波电容重新布线设备频繁离线再上线心跳间隔太长或网络不稳定确认30秒发送一次checkin报文DHT11偶尔读失败时序不满足或线太长用DWT/定时器做微秒延时缩短数据线5.3 实际调试中的三个心得第一个心得是关于串口打印日志的重要性。我在整个开发过程中始终保留了USART2作为调试串口任何关键事件的执行都加了一行日志比如“DHT11 read complete: temp26 humi58”“Send to ESP8266: {json报文内容}”“Recv from ESP8266: {收到的原始数据}”。打印出来的内容用串口助手的“时间戳”功能打上时间标记整个系统的行为、时序一目了然。很多问题看一眼日志就能瞬间定位比用示波器、逻辑分析仪快得多。第二个心得是善用串口助手的定时发送功能来模拟ESP8266收到服务器指令的场景。在联调指令下发时我没有急着用App发而是先用电脑串口助手按照{M:cmd,ID:123,C:{LED:开}}的格式手动发送给STM32连接的串口在开发时先暂时把ESP8266拔掉用USB转TTL直连STM32。如果STM32能正确解析并控制继电器说明单片机端代码没问题再回头排查ESP8266和服务器部分。这样把“下行链路”切成了三段逐一验证我大概用两次就把整个链路跑通了。第三个心得是DHT11的读取出错时不要急着怀疑代码。先用串口助手确认一下DHT11的上电速度和时序容忍度。DHT11上电后需要1秒稳定时间而且两次读取间隔必须大于1秒。如果你在初始化后立即连续读取多次第二、第三次读取确实会失败。我最初的代码就把DHT11获取放在了主循环开头导致系统上电后前几次读取全是失败报了一堆Error其实只要加一个1秒的初始延时再读就解决了。6. 项目功能的扩展方向与答辩加分项6.1 数据可视化与历史记录如果你答辩时只演示一个App上的实时数据卡片评委大概率会追问“数据能存下来吗”“能不能看历史曲线”。贝壳物联本身提供了一些数据展示功能但免费版本比较弱只能看最近的数据。如果你想让项目更有深度我建议用贝壳物联的开放接口或者把数据转存到本地服务器/云数据库中然后用一个简单的Web页面展示历史曲线和统计报表。最简单的做法是在STM32上报数据的同时通过另一个串口或者USB虚拟串口把数据转发到电脑上的一个Python脚本脚本接收后写入SQLite再用Flask或Dash做一个简单的Web页面展示温度、湿度、光照的历史曲线。这个功能如果做了答辩时的层次感立刻不一样因为它展示了你对完整物联网数据链路的理解而不只是“设备能上网”。6.2 多设备组网与场景联动贝壳物联支持多设备接入也就是说你可以不只做一个节点。比如做一个主控制节点加两个子节点分别放在客厅、卧室和厨房每个节点采集本地的温湿度、光照、烟雾数据并控制本地的继电器设备。主节点通过一个简单的串口总线或者WiFi UDP把各节点的数据汇总后上报。场景联动的玩法也能加分。比如贝壳物联App上定义一个“回家模式”指令STM32收到后自动执行一组动作打开客厅灯光、打开风扇、设置空调温控阈值、解除烟雾报警联动。这个逻辑写起来很简单就是解析指令后依次执行一堆GPIO操作但体现出了系统集成的思维评委很吃这一套。6.3 本地语音控制与离线自动化如果你不想完全依赖云端的指令链路还可以加一个离线语音识别方案。比如用SU-03T这类离线语音识别模块本地识别“开灯”“关灯”“温度多少”等语音命令然后用串口告诉STM32执行。这样系统在断网时也能实现基本的语音控制可靠性更高。这个扩展点很具亮点因为很多毕设是纯云端的一旦断网设备就傻了你能做离线兜底方案说明你考虑了实际产品的工程落地问题。6.4 低功耗与电池供电优化如果你想让项目更接近真实产品可以优化功耗STM32进入待机模式定时唤醒采集数据后发送传感器供电用MOS管控制平时不供电采集时才通电ESP8266支持Modem Sleep模式配置好之后可以大幅降低功耗。这一块如果在论文里专门拿一节写功耗测试数据和优化策略是一个非常不错的亮点。7. 完整源码结构与关键代码说明7.1 工程目录结构按模块化方式组织代码不要把所有函数堆在main.c里否则答辩时被问“你这个工程怎么组织的”就会露馅。我的推荐目录结构是这样的Project/ ├── Core/ │ ├── Inc/ │ ├── Src/ │ │ ├── main.c │ │ ├── gpio.c │ │ ├── adc.c │ │ └── usart.c ├── Drivers/ │ └── STM32F1xx_HAL_Driver/ ├── Middlewares/ ├── USER/ │ ├── bsp_dht11.c │ ├── bsp_esp8266.c │ ├── bsp_oled.c │ ├── protocol_iot.c │ ├── protocol_sensor.c │ └── systime.c关键的HAL库初始化文件放在Core里由CubeMX管理自己写的驱动统一放在USER文件夹。这样CubeMX重新生成代码时USER里的驱动文件不会被覆盖也不用每次都加USER CODE BEGIN。7.2 关键代码片段ESP8266指令发送与状态机接收这是项目里最重要的一段代码。ESP8266发送数据时我用了一个带超时的发送函数确保不会因为模块忙导致发送失败uint8_t ESP8266_SendCommand(char* cmd, char* expected, uint16_t timeout_ms) { uint8_t ret 0; memset(rx_buf, 0, RX_BUF_MAX); rx_len 0; HAL_UART_Transmit(huart1, (uint8_t*)cmd, strlen(cmd), 1000); if(expected NULL) return 1; uint32_t start GetTick(); while(GetTick() - start timeout_ms) { if(rx_len 0 strstr((char*)rx_buf, expected) ! NULL) { ret 1; break; } } return ret; }在透传模式下这个函数依然可以用来发送数据到TCP连接只不过不用检查OK返回值发送完直接继续。注意发送数据时尽量不要在数据里包含\r\n之外的控制字符否则会被ESP8266当成AT指令来解释。命令接收中断我用的标准写法void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1) { iot_rx_buf[iot_rx_len] iot_rx_byte; HAL_UART_Receive_IT(huart1, iot_rx_byte, 1); } }主循环里不断调用IoT_ParseData()函数逐字节解析接收缓冲区里的数据。解析的JSON我并没有用cJSON库而是用了简单字符串查找函数strstr来提取关键字段。因为贝壳物联的指令格式非常固定我只需要查找C后面的内容再提取指令点名称和值。用cJSON会显得更专业但也会引入额外的内存开销对F103这种小内存芯片不太友好。7.3 主循环与整体调度项目的核心控制逻辑就是一个简单的前后台调度不跑OS但要有清晰的调度逻辑。主循环大概是这样的int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); MX_DMA_Init(); MX_I2C1_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); OLED_Init(); OLED_ShowString(0, 0, Smart Home); HAL_UART_Receive_IT(huart1, iot_rx_byte, 1); ESP8266_Init(); IoT_Checkin(); uint32_t lastSensorTick 0; uint32_t lastHeartTick 0; uint32_t lastDisplayTick 0; while(1) { // 解析串口收到的云端指令 IoT_ParseCmd(); // 每3秒采集发送一次数据 if(GetTick() - lastSensorTick 3000) { Sensor_ReadAll(); IoT_UpdateData(); lastSensorTick GetTick(); } // 每30秒发送一次心跳 if(GetTick() - lastHeartTick 30000) { IoT_Checkin(); lastHeartTick GetTick(); } // 每500ms刷新OLED显示 if(GetTick() - lastDisplayTick 500) { OLED_Refresh(); lastDisplayTick GetTick(); } // 烟雾浓度超阈值则报警 if(sensor_value.smoke SMOKE_THRESHOLD) { HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin, GPIO_PIN_RESET); } } }这个结构任何面试官问起来都能讲得头头是道因为它体现了嵌入式系统的裸机调度思想时间片轮询、状态标志位、非阻塞延时。8. 论文和答辩准备的一些建议这个项目本身已经涵盖了一个物联网毕设的全部要素如果你时间还充裕论文可以从以下几个方面展开每一章都能写得有内容可查。第一章绪论里不要把背景写得太大太空重点讲智能家居行业的痛点是“设备孤岛、交互复杂、成本偏高”。第二章重点讲总体方案设计用数据流图说明整个系统的工作流程再说明为什么选STM32和贝壳物联对比ESP32方案时记得从学习价值、功耗、外设资源等角度出发。第三章是硬件设计给出每个模块的电路连接图以及电源树设计算一下总功耗。第四章是软件设计按模块讲每个模块分“原理、实现、关键代码”三个小节。第五章是系统测试建议做一个对比表格把“设定值”和“实测值”放在一起比对比如恒温控制时设定26度实测24.8度误差多少。这个表一放实验说服力直接拉满。第六章是总结与展望。答辩时最重要的是操作演示的流畅性。我的经验是务必给自己定一个标准演示脚本按固定顺序操作不要临时发挥。比如先展示硬件全貌再打开手机App展示设备在线状态然后指着传感器和设备说“现在我对着传感器哈一口气温度上升”“用手电筒照光敏电阻光照ADC值变化”“按下App开关继电器吸合亮灯”。每一步操作前先在内心预演一遍确保设备已经连接、App已经打开在正确页面。如果演示中途设备恰好掉线赶紧说“我们等一下看OLED上显示的本地数据这正说明了我这个系统在断网时也能继续工作”把尴尬转化为展示亮点。我另外再提一个细节提交的工程压缩包和代码里务必要写清楚README。我在评审过的一个项目里见过代码写得不错但压缩包里乱成一团评审光找入口文件就花了十分钟印象分直接掉一半。README里写清楚四件事硬件清单、接线方式、CubeMX配置步骤、使用方法。将来说明你在做的时候打开你的文档能直接复现这就是工程素养的体现。最后说点真话我见过太多人做智能家居毕设做得差不多就停了代码能跑起来就交差。但如果你想真正从这个项目里学到东西就多花一点时间把“如果服务器连不上怎么办”“如果传感器坏了怎么办”“如果断电再上电怎么办”这些异常场景都想一遍写进代码里。这些才是真实嵌入式工程师每天都在处理的问题也是答辩、面试时拉开差距的地方。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻