
1. 项目缘起与整体设计思路1.1 为什么选STM32加Zigbee这套组合做智能家居环境监测这个方向选型阶段其实是最磨人的。市面上能跑通的方案不少ESP32自带WiFi、LoRa远距离传输、蓝牙Mesh组网每一种都有各自的适用场景。我最终敲定STM32加Zigbee核心原因有三个低功耗常驻运行、组网稳定不挑路由器、节点扩展灵活。STM32的功耗控制是它相比ESP32最大的优势。ESP32跑WiFi的时候峰值电流能到200mA以上就算用深度睡眠模式唤醒联网那一下也不省电。而STM32L系列或者F系列配合Zigbee模块终端节点休眠电流可以压到微安级别两节五号电池撑半年以上不是问题。环境监测这种场景温湿度、空气质量这些数据变化本来就慢没必要一直在线定时上报就够了。Zigbee这边它天生就是为低速率、低功耗、自组网设计的。跟WiFi比Zigbee不占用2.4G频段那点拥挤的信道虽然也工作在2.4G但它是跳频加Mesh组网一个节点挂了其他节点自动绕路。跟蓝牙比Zigbee的Mesh组网能力更强节点数量理论上可以到65535个家庭环境几十个节点绰绰有余。而且Zigbee模块现在价格很便宜CC2530核心板十几块钱就能拿下批量做成本可控。注意选Zigbee模块的时候一定要确认协议栈版本。CC2530用的是Z-Stack协议栈TI官方已经不怎么更新了但社区资料多踩坑容易找到答案。如果预算充足可以考虑CC2652或者EFR32系列协议栈更新更勤快但入门门槛高一些。1.2 系统整体架构怎么搭整个系统我分成三层感知层、网络层、应用层。这个分层不是照搬教科书是实际调试下来最顺手的组织方式。感知层就是各个终端节点每个节点一颗STM32最小系统板加传感器加Zigbee模块。传感器这块我选了DHT22测温湿度、MQ-135测空气质量、BH1750测光照强度。DHT22比DHT11精度高温度误差正负0.5度湿度误差正负2%做环境监测够用了。MQ-135对氨气、苯系物、烟雾都有响应虽然不能精确到具体浓度但做趋势判断和超标报警没问题。BH1750是数字光照传感器I2C接口比光敏电阻线性度好太多。网络层就是Zigbee协调器和路由器。协调器负责建网和管理路由器负责中继。家庭环境一般一个协调器加一两个路由器就能覆盖一百多平。协调器通过串口跟STM32网关通信网关再通过串口或者网口把数据传到上位机。应用层我做了两个版本一个是本地LCD屏显示加蜂鸣器报警另一个是上位机软件。上位机用Qt写的串口接收数据实时曲线显示数据存SQLite数据库。这样既能脱机运行也能连电脑看历史数据。1.3 方案选型背后的取舍逻辑有人可能会问为什么不直接用ESP32加WiFi一个芯片全搞定成本还低。这个问题我实际对比过。ESP32方案确实简单但有两个硬伤一是WiFi配网麻烦家里换个路由器密码所有节点都要重新配二是WiFi功耗高电池供电撑不住。Zigbee方案虽然多了一颗STM32和一颗Zigbee模块但分工明确。STM32负责传感器采集和逻辑控制Zigbee负责组网传输各干各的。而且Zigbee网络一旦建好加节点就是上电自动入网不用重新配置。这个在后期扩展的时候优势特别明显。还有一点STM32的资料生态太丰富了。江科大的教程、正点原子的例程、ST官方的HAL库遇到问题搜一下基本都有答案。Zigbee这边虽然资料少一些但CC2530的Z-Stack协议栈是开源的底层能改灵活性高。实操心得如果你也是第一次做Zigbee项目建议先买两块CC2530核心板加一个USB转串口底板把协调器和终端的基本通信跑通再往上加STM32。不要一上来就画PCB打板调试阶段用杜邦线连就行等软件跑通了再考虑硬件集成。2. 核心硬件选型与电路设计要点2.1 STM32主控怎么选型STM32型号太多了F103、F407、L051、G030选哪个合适我的建议是看你的传感器接口和功耗要求。如果传感器都是I2C或者SPI接口F103C8T6这颗经典款完全够用。72MHz主频64KB Flash20KB RAM价格十块钱左右最小系统板满天飞。我第一版就是用F103C8T6做的跑传感器采集加串口通信毫无压力。如果要做低功耗电池供电那就选L系列比如STM32L051C8T6。这颗芯片跑32MHzFlash 64KB关键是低功耗模式做得很好。Stop模式下电流不到1微安RTC走时加定时唤醒平均电流可以做到几十微安。两节2000mAh的电池理论续航能到两年以上。如果传感器多、数据量大需要跑RTOS那就上F407或者G474。F407是M4内核168MHz带FPU做数据处理快很多。G474是M4内核加数学加速器适合做信号处理。我最终用的是STM32F103C8T6做终端节点STM32F407VET6做网关。终端节点不需要太强算力F103够用还便宜。网关要跑协议转换和数据缓存F407的RAM和Flash都大一些跑起来从容。2.2 Zigbee模块选型与对比Zigbee模块市面上主流的有CC2530、CC2531、CC2652、EFR32MG21这几款。我整理了一个对比表方便你选型的时候参考。模块型号核心芯片协议栈发射功率接收灵敏度价格区间适用场景CC2530CC2530F256Z-Stack4.5dBm-97dBm10-20元入门学习、小规模组网CC2531CC2531F256Z-Stack4.5dBm-97dBm15-25元带USB接口适合做协调器CC2652CC2652RZ-Stack 3.05dBm-100dBm30-50元中大规模组网、低功耗EFR32MG21EFR32MG21EmberZNet10dBm-102dBm40-60元高性能、远距离CC2530是入门首选资料最多Z-Stack协议栈虽然老但稳定。缺点是RAM只有8KB跑复杂应用有点吃力。CC2652是升级款RAM 80KBFlash 352KB跑Z-Stack 3.0支持更多节点和更复杂的应用。EFR32MG21发射功率高穿墙能力强适合大户型。我用的CC2530加PA功放发射功率能到20dBm穿两堵墙没问题。PA功放芯片用的是CC2591TI官方有参考设计照着抄就行。注意CC2530的Z-Stack协议栈默认发射功率是4.5dBm如果要加PA需要在协议栈里改宏定义。具体是在mac_radio_defs.h里把MAC_RADIO_TX_POWER_DEFAULT改成对应的值。改完要重新编译协调器和终端固件两边都要改。2.3 传感器电路设计避坑传感器电路这块我踩过几个坑分享出来帮你省时间。DHT22的供电电压是3.3V到5.5V但它的数据线是开漏输出必须接上拉电阻。我一开始没接数据读出来全是0。上拉电阻用4.7K到10K都行我用的10K稳定。数据线长度不要超过20米太长信号质量下降。如果传感器离STM32远中间加个缓冲器或者用屏蔽线。MQ-135是模拟传感器输出0到5V的模拟电压。STM32的ADC参考电压是3.3V直接接会把超过3.3V的部分削掉。我一开始没注意读出来的空气质量数据一直偏高。后来加了个电阻分压把5V分到3.3V以内。分压电阻用10K和20K分压比1比35V进来变成3.33V刚好在量程内。BH1750是I2C接口地址是0x23或者0x5C取决于ADDR引脚接高还是接低。I2C总线上要接上拉电阻4.7K到10K。如果总线上挂多个I2C设备上拉电阻只接一组就行不要每个设备都接否则等效电阻太小总线拉不低。实操心得画PCB的时候传感器的电源引脚旁边一定要放0.1uF的去耦电容越近越好。DHT22和MQ-135对电源噪声敏感去耦电容能明显改善数据稳定性。我第一版没放温湿度数据偶尔跳变加了电容之后就稳了。2.4 电源管理设计电源这块分两种情况市电供电和电池供电。市电供电简单5V适配器进来经过AMS1117-3.3降到3.3V给STM32和传感器供电。AMS1117的输入输出压差要大于1V5V转3.3V没问题。输出端要接10uF钽电容加0.1uF陶瓷电容钽电容负责低频滤波陶瓷电容负责高频。有人问钽电容能不能换成陶瓷电容可以但容值要够建议22uF以上否则负载突变的时候电压会掉。电池供电就要考虑低功耗了。我用的是两节五号电池串联3V供电。STM32L051可以直接跑在3V不需要升压。Zigbee模块CC2530最低工作电压是2.0V3V也在范围内。传感器DHT22最低2.4VMQ-135需要5V所以电池供电版本我去掉了MQ-135只保留温湿度和光照。低功耗策略是STM32定时唤醒比如每5分钟醒一次采集数据通过Zigbee发出去然后继续休眠。Zigbee终端节点也配置成休眠模式跟STM32同步唤醒。这样平均电流可以做到50微安左右两节2000mAh电池理论续航超过两年。注意STM32进入Stop模式之前要把所有不用的外设时钟关掉GPIO配置成模拟输入或者输出低电平避免漏电流。我实测过一个浮空的GPIO引脚能带来几十微安的漏电流几个引脚加起来就上百微安了续航直接砍半。3. 软件架构与核心代码实现3.1 STM32端传感器驱动开发STM32端的软件我用HAL库开发Keil MDK编译。开发环境搭建这块Keil5安装STM32芯片包是第一步。如果你同时要开发C51和STM32Keil5可以兼容但要注意安装路径不要有中文和空格否则芯片包安装会失败。DHT22的驱动是单总线协议时序要求比较严格。我用的是TIM定时器做微秒延时比空循环准。DHT22的起始信号是拉低至少18毫秒然后拉高20到40微秒然后释放总线。DHT22响应是拉低80微秒然后拉高80微秒然后开始传数据。每个bit是50微秒低电平加不同长度的高电平高电平26到28微秒是070微秒是1。// DHT22读取温湿度核心代码 uint8_t DHT22_ReadByte(void) { uint8_t i, byte 0; for(i 0; i 8; i) { while(!DHT22_PIN); // 等待50us低电平结束 Delay_us(40); // 延时40us判断高电平长度 byte 1; if(DHT22_PIN) // 如果还是高电平说明是1 { byte | 1; while(DHT22_PIN); // 等待高电平结束 } } return byte; }MQ-135的驱动就简单了ADC采集加滑动平均滤波。我用的ADC1的通道012位分辨率采样时间239.5个周期。采集10次取平均然后做温度补偿。MQ-135的输出受温湿度影响DHT22测到的温湿度可以用来修正。BH1750的驱动是标准I2C连续读取模式分辨率选高精度模式测量时间120毫秒。读取的时候先发设备地址加写标志然后发命令字0x10然后发设备地址加读标志读两个字节高字节在前。实操心得DHT22读取间隔不要小于2秒否则传感器会发热湿度读数偏高。我一开始每500毫秒读一次湿度一直比实际高10%左右改成5秒读一次就正常了。另外DHT22上电后要等1秒再读刚上电的时候数据不稳定。3.2 Zigbee组网与数据传输Zigbee这边我用的是Z-Stack协议栈版本是2.5.1a。协调器负责建网终端节点负责入网和数据发送。协调器建网流程初始化协议栈设置PAN ID和信道调用NLME_NetworkFormationRequest建网。建网成功后协调器的短地址固定是0x0000。终端节点上电后调用NLME_NetworkDiscoveryRequest扫描网络找到协调器后调用NLME_JoinRequest入网。入网成功后终端节点会得到一个16位的短地址。数据传输我用的是点对点模式终端节点直接发数据给协调器。数据发送用AF_DataRequest函数目标地址填协调器的短地址0x0000端点号填1簇ID填0x0001。协调器收到数据后通过串口转发给STM32网关。// Zigbee终端节点发送数据 void Zigbee_SendData(uint8_t *data, uint8_t len) { afAddrType_t destAddr; destAddr.addrMode afAddr16Bit; destAddr.addr.shortAddr 0x0000; // 协调器地址 destAddr.endPoint 1; AF_DataRequest(destAddr, SampleApp_epDesc, 0x0001, len, data, SampleApp_TransID, AF_DISCV_ROUTE, AF_DEFAULT_RADIUS); }协调器收到数据后通过串口发给STM32网关。串口波特率我用的115200数据格式是帧头0xAA 0x55然后节点地址2字节传感器类型1字节数据4字节校验和1字节帧尾0x55 0xAA。这个格式是我自己定的简单够用。注意Zigbee的信道要和WiFi错开。WiFi常用1、6、11信道对应Zigbee的信道是12、17、22。我一开始没注意Zigbee和路由器信道重叠丢包率很高。后来把Zigbee信道设成15和25稳定多了。在Z-Stack里改信道是在f8wConfig.cfg文件里改-DDEFAULT_CHANLIST0x000008000x00000800对应信道110x00002000对应信道13以此类推。3.3 网关数据汇聚与协议转换STM32网关这边跑的是FreeRTOS三个任务串口接收任务、数据处理任务、上位机通信任务。串口接收任务用DMA加空闲中断收到一帧数据后解析。解析的时候先找帧头然后读长度然后校验校验通过后把数据放到消息队列。数据处理任务从消息队列取数据根据节点地址和传感器类型把数据存到对应的结构体里。上位机通信任务定时把数据打包发出去。协议转换这块Zigbee的数据格式和上位机的数据格式不一样。Zigbee那边是二进制上位机这边我用的是JSON格式方便解析。转换的时候把二进制数据转成JSON字符串比如{node:0x0001,temp:25.6,humi:60.2,light:320}。// 二进制转JSON void BinToJson(uint8_t *bin, char *json) { uint16_t nodeAddr (bin[0] 8) | bin[1]; uint8_t sensorType bin[2]; float value *(float*)bin[3]; sprintf(json, {\node\:\0x%04X\,\type\:%d,\value\:%.2f}, nodeAddr, sensorType, value); }上位机通信我用的是串口波特率115200。如果要做网络通信可以加个以太网模块比如W5500SPI接口STM32驱动起来也方便。不过家庭环境串口够用了没必要上以太网。实操心得FreeRTOS的任务堆栈大小要留够。我一开始串口接收任务堆栈只给了128字跑起来偶尔HardFault。后来改成256字就稳了。堆栈大小可以在xTaskCreate的第三个参数里改单位是字不是字节。STM32F407的RAM是192KB多给点堆栈不心疼。3.4 上位机软件设计上位机我用Qt写的跨平台Windows和Linux都能跑。主要功能串口配置、实时数据显示、历史曲线、数据导出。串口配置用QSerialPort类扫描可用串口设置波特率、数据位、停止位、校验位。打开串口后用readyRead信号触发读取读到数据后解析JSON。实时数据显示用QLabel和QProgressBar温度、湿度、光照、空气质量各一个。数据更新的时候刷新界面。历史曲线用QCustomPlotX轴是时间Y轴是数值可以同时显示多条曲线。数据存储用SQLite建一张表字段是时间戳、节点地址、传感器类型、数值。插入数据用事务批量插入比单条插入快很多。我实测过单条插入1000条数据要3秒多用事务只要0.1秒。// Qt串口读取 void MainWindow::onSerialReadyRead() { QByteArray data serial-readAll(); buffer.append(data); while(buffer.contains(\n)) { int pos buffer.indexOf(\n); QByteArray line buffer.left(pos); buffer.remove(0, pos 1); QJsonDocument doc QJsonDocument::fromJson(line); if(!doc.isNull()) { QJsonObject obj doc.object(); updateUI(obj); saveToDatabase(obj); } } }注意Qt的串口读取要在单独的线程里做不要在主线程里阻塞读取。我一开始在主线程里用waitForReadyRead界面直接卡死。后来改成信号槽异步读取界面流畅多了。另外串口数据要用缓冲区拼接因为一次readyRead可能只收到半帧数据。4. 系统调试与常见问题排查4.1 Zigbee组网失败排查Zigbee组网失败是最常见的问题我遇到过好几次总结下来主要有这几个原因。协调器没建网成功。协调器上电后如果PAN ID冲突或者信道被占用建网会失败。排查方法是看协调器的LED指示灯如果一直快闪说明在扫描网络如果慢闪说明建网成功如果不亮说明没跑起来。可以用Z-Stack的MT命令查看状态串口发MT_NLME_NETWORK_FORMATION看返回的状态码。终端节点入网失败。终端节点入网失败通常是协调器不在允许入网状态。协调器默认只允许入网60秒过了这个时间就不让入了。解决方法是在协调器上电后60秒内给终端节点上电或者改代码把允许入网时间设长一点。在ZDApp_Init里改zgDefaultStartingScanDuration和zgDefaultChannelList。入网后通信不稳定。这个通常是信道干扰或者距离太远。先用MT_NLME_NETWORK_DISCOVERY扫描一下周围网络看有没有同信道的WiFi。如果有换个信道。距离太远就加路由器Zigbee路由器会自动中继。问题现象可能原因排查方法解决方案协调器LED不亮供电不足或固件没烧录测电压、重新烧录换电源、重新烧录固件协调器LED快闪不停建网失败查PAN ID冲突、信道占用改PAN ID、换信道终端节点入网失败协调器不允许入网查协调器入网时间60秒内上电或改代码通信丢包严重信道干扰、距离远扫描周围网络换信道、加路由器数据偶尔错误电源噪声、天线匹配查电源纹波、天线阻抗加去耦电容、调天线实操心得CC2530的天线匹配很重要。我用的是PCB板载天线按照TI的参考设计画的但实际调试的时候发现距离只有十几米。后来用频谱仪看了一下天线谐振点偏了调整了匹配电容就好了。如果没有频谱仪可以先用外置天线SMA接口的2.4G天线拧上去就能用距离能到几十米。4.2 STM32程序下载与调试问题STM32下载程序常见的问题有几个。ST-Link识别不到芯片。这个通常是接线问题或者芯片没供电。ST-Link的SWD接口需要接四根线3.3V、GND、SWDIO、SWCLK。检查接线测芯片供电电压。如果都正常还是识别不到可能是芯片被锁了用ST-Link Utility擦除全片。Keil5编译报错找不到芯片包。这个是因为Keil5没有安装对应的芯片包。打开Keil5的Pack Installer搜索STM32F1安装对应的DFP包。如果安装失败检查网络或者手动下载pack文件双击安装。程序下载后不运行。检查BOOT0和BOOT1引脚BOOT0要接低电平从Flash启动。如果BOOT0接高芯片会进入系统存储器启动模式不跑用户程序。另外检查复位电路复位引脚要接10K上拉加0.1uF电容。串口打印乱码。检查波特率是否匹配STM32的串口波特率要和上位机一致。检查晶振频率HAL库初始化的时候要填正确的晶振频率否则波特率会偏。我用的8MHz晶振HSE_VALUE要改成8000000。注意STM32的JTAG引脚和GPIO复用。如果用了PA13、PA14、PA15、PB3、PB4这几个引脚做普通GPIO要先禁用JTAG。在GPIO_Init之前调用__HAL_AFIO_REMAP_SWJ_NOJTAG()只保留SWD。否则这几个引脚不受GPIO控制。4.3 传感器数据异常处理传感器数据异常也是高频问题。DHT22读出来全是0或者全是1。检查上拉电阻数据线要接4.7K到10K上拉。检查时序DHT22对时序敏感延时函数要准。用示波器看波形起始信号低电平要够18毫秒高电平20到40微秒。MQ-135读数一直偏高。检查分压电阻5V输出要分压到3.3V以内。检查预热时间MQ-135需要预热24小时以上才能稳定。我一开始没预热读数漂得厉害预热一天后就稳了。BH1750读数不变。检查I2C地址ADDR引脚接低是0x23接高是0x5C。检查I2C上拉电阻SDA和SCL都要接4.7K上拉。检查测量模式连续高精度模式测量时间120毫秒读太快会读到旧数据。传感器异常现象排查方法解决方案DHT22数据全0或全1查上拉电阻、时序加上拉、调延时DHT22湿度偏高查读取间隔间隔大于2秒MQ-135读数偏高查分压电阻加分压电路MQ-135读数漂移查预热时间预热24小时BH1750读数不变查I2C地址、模式改地址、改模式BH1750读数跳变查电源噪声加去耦电容实操心得传感器数据最好做软件滤波。我用的是中值滤波加滑动平均先连续读5次去掉最大最小值剩下3个取平均。这样能滤掉大部分突发干扰。滤波窗口不要太大否则响应变慢。温湿度这种慢变量窗口可以大一点光照这种快变量窗口要小。4.4 低功耗调试与优化低功耗调试是电池供电版本的关键。实测电流比预期高。用万用表测电流逐个排查。先测STM32单独运行的电流再测加Zigbee模块的电流再测加传感器的电流。找出哪个部分耗电多。STM32 Stop模式电流高。检查GPIO配置浮空的引脚要配置成模拟输入或者输出低。检查外设时钟不用的外设时钟要关掉。检查调试接口SWD接口在低功耗模式下也会耗电可以在DBGMCU_CR里关掉。Zigbee终端节点休眠电流高。检查Z-Stack的电源管理配置POWER_SAVING宏要打开。检查轮询周期NLME_SetPollRate设置轮询间隔间隔越长越省电。检查发射功率发射功率越高越耗电够用就行。我实测的数据STM32L051在Stop模式下电流1.2微安CC2530在PM2模式下电流0.8微安DHT22待机电流1微安BH1750待机电流0.5微安。加起来不到5微安。唤醒的时候STM32跑32MHz电流约5毫安CC2530发射电流约30毫安DHT22测量电流约1毫安。假设每5分钟唤醒一次每次工作200毫秒平均电流约50微安。两节2000mAh电池理论续航2000/0.0540000小时约4.5年。实际打对折两年没问题。注意低功耗调试的时候万用表要串在电源回路里用微安档。普通万用表的微安档内阻大会影响电路工作最好用专门的功耗分析仪。如果没有可以用示波器加采样电阻测电阻两端的电压波形然后算电流。5. 系统扩展与进阶玩法5.1 接入更多传感器类型基础版跑通之后可以加更多传感器。我后来加了人体红外传感器HC-SR501、烟雾传感器MQ-2、水浸传感器。HC-SR501是数字输出有人移动输出高电平没人输出低电平。接STM32的GPIO配置成外部中断有人移动的时候唤醒STM32。这个做安防联动很好用晚上检测到有人移动就开灯。MQ-2和MQ-135类似模拟输出测烟雾和可燃气体。电路和MQ-135一样加个分压电阻就行。MQ-2对液化气、丙烷、氢气都敏感做厨房安全监测合适。水浸传感器是数字输出检测到水输出高电平。放在厨房和卫生间漏水的时候报警。这个传感器简单两根探针遇水导通。实操心得加传感器的时候注意STM32的引脚资源。F103C8T6只有37个GPIOI2C、SPI、UART占掉一些剩下的不多。如果传感器多可以用I2C扩展芯片比如PCF8574一个I2C转8个GPIO。或者用SPI扩展74HC595串转并。5.2 接入云平台与远程监控本地跑通之后可以接云平台做远程监控。我用的是MQTT协议网关通过以太网或者4G模块连到MQTT服务器。MQTT服务器可以自己搭用Mosquitto开源免费。也可以买云服务阿里云、腾讯云都有物联网平台有免费额度。自己搭的话在树莓派上装Mosquitto配置一下就行。网关这边STM32跑MQTT客户端。MQTT协议不复杂CONNECT、PUBLISH、SUBSCRIBE、PINGREQ这几个报文。可以用现成的MQTT库比如Paho MQTT Embedded C移植到STM32上。数据上传格式用JSON主题用home/sensor/节点地址。比如home/sensor/0x0001消息内容是{temp:25.6,humi:60.2}。手机装个MQTT客户端订阅这个主题就能远程看数据了。注意MQTT的Keep Alive时间要设合理。太短了频繁发PINGREQ耗电太长了服务器会断开连接。我设的是60秒平衡了功耗和连接稳定性。另外MQTT的QoS等级环境监测用QoS 0就够了丢了就丢了下次上报补上。5.3 本地自动化联动环境监测不只是看数据还可以做自动化联动。我在网关里加了规则引擎简单几条规则。温度高于30度自动开空调。通过红外发射模块发射空调遥控码。红外发射管接STM32的PWM输出38K载波调制。遥控码用逻辑分析仪抓一次存到数组里需要的时候发出去。湿度低于40%自动开加湿器。加湿器用继电器控制STM32的GPIO驱动继电器模块。继电器模块选光耦隔离的避免干扰STM32。空气质量超标自动开新风系统。新风系统也是继电器控制逻辑和加湿器一样。// 简单规则引擎 void RuleEngine(void) { if(temp 30.0 !acOn) { AC_On(); acOn 1; } else if(temp 26.0 acOn) { AC_Off(); acOn 0; } if(humi 40.0 !humidifierOn) { Humidifier_On(); humidifierOn 1; } else if(humi 60.0 humidifierOn) { Humidifier_Off(); humidifierOn 0; } }实操心得自动化联动一定要加迟滞否则会在阈值附近反复开关。比如温度高于30度开空调低于26度关空调中间4度是迟滞区间。没有迟滞的话温度在30度上下波动空调会频繁启停压缩机容易坏。5.4 数据可视化与报表生成上位机这边可以加数据可视化用Qt的QChart或者QCustomPlot画曲线。我用的QCustomPlot性能好支持实时刷新。历史数据查询用SQLite的SQL语句按时间范围查。查出来的数据画曲线可以同时显示多个节点的数据用不同颜色区分。报表生成用QPrinter把曲线和数据表格打印成PDF。或者导出CSV用Excel打开做进一步分析。CSV格式简单逗号分隔Excel直接能读。// 导出CSV void MainWindow::exportCSV() { QString fileName QFileDialog::getSaveFileName(this, 导出CSV, , CSV文件 (*.csv)); if(fileName.isEmpty()) return; QFile file(fileName); if(!file.open(QIODevice::WriteOnly | QIODevice::Text)) return; QTextStream out(file); out 时间,节点,温度,湿度,光照,空气质量\n; QSqlQuery query(SELECT * FROM sensor_data ORDER BY timestamp); while(query.next()) { out query.value(timestamp).toString() , query.value(node).toString() , query.value(temp).toString() , query.value(humi).toString() , query.value(light).toString() , query.value(air).toString() \n; } file.close(); }注意SQLite数据库文件会越来越大要定期清理。我设的是保留最近30天的数据超过30天的自动删除。删除的时候用DELETE FROM sensor_data WHERE timestamp date(now, -30 days)然后VACUUM回收空间。不VACUUM的话数据库文件不会变小。6. 项目总结与个人体会这个项目从选型到跑通前前后后花了大概两个月。中间踩了不少坑也学到了很多东西。最大的体会是Zigbee组网比想象中麻烦但一旦跑通就很稳。刚开始调Zigbee的时候终端节点死活入不了网查了两天才发现是协调器的允许入网时间过了。后来把允许入网时间改成一直允许问题就解决了。Zigbee的Mesh组网确实强我在客厅放协调器卧室放路由器阳台的终端节点通过路由器中继信号满格。STM32的低功耗比想象中好调但细节很多。Stop模式电流能到微安级但前提是所有GPIO都配置对了。我一开始有几个引脚浮空电流一直降不下来后来逐个排查才找到。低功耗调试要有耐心一个引脚一个引脚地测。传感器数据滤波很重要。原始数据跳变厉害不做滤波根本没法用。中值滤波加滑动平均简单有效。滤波窗口大小要调不同传感器不一样。上位机用Qt开发效率高。Qt的串口、数据库、绘图模块都很成熟文档也全。QCustomPlot画实时曲线性能好几千个点不卡。最后分享一个小技巧调试的时候在STM32里加个printf重定向到串口把关键变量打出来。比用调试器单步跟踪快多了。重定向就是实现fputc函数把字符写到串口。Keil里勾选Use MicroLIB就能用printf了。// printf重定向 int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t*)ch, 1, 1000); return ch; }这个项目后续还可以扩展比如加语音控制、加摄像头、接Home Assistant。环境监测只是智能家居的一个切入点把数据采集和传输跑通了后面加什么功能都是搭积木。