简介:本资源是一份基于STM32的养殖场环境监测系统完整项目文档,面向物联网、嵌入式开发学习者及毕业设计开发者,帮助解决环境参数采集、远程监控与智能控制等实际问题。文档以STM32F103RCT6为主控,整合SHT30温湿度、MQ135空气质量、BH1750光照等传感器,并借助ESP8266-WIFI模块通过MQTT协议将数据上传至华为云物联网平台,支持Android与Windows端远程查看与控制。资源包共1个PDF文件,约50.43MB,内容涵盖项目背景、功能设计、硬件模块组成、系统原理图、框架图与实物模型图等,结构完整,便于按模块查阅。目前已有311人学习下载。读者可从中获取从传感器驱动、OLED显示、自动与手动模式切换,到云端数据存储、远程设备控制及智能报警的完整实现思路,适合作为课程设计、竞赛项目或养殖智能化改造的参考方案。
1. 养殖场环境监测为什么值得用 STM32 加云平台重做一遍
很多做嵌入式的人都接过类似的活:一个养殖场老板说,夏天棚里温度一高,鸡就开始扎堆喘气,等工人发现的时候已经死了几十只。传统做法是挂几个温湿度计,靠人定时去抄表,问题是人不可能 24 小时盯着,夜里和凌晨的异常基本靠运气发现。这套「267 基于 STM32 设计的养殖场环境监测系统(华为云 IOT)」要解决的,就是把温湿度、氨气、光照这些指标自动采上来,本地判断、本地报警,同时通过物联网平台把数据推到云端,让老板在手机上就能看到每个棚的实时状态。
它适合谁?一类是做嵌入式课程设计或毕设的人,需要一套从传感器到云端的完整链路;另一类是真的想给中小养殖场做低成本改造的工程师,预算有限、现场没有稳定有线网络、也不希望数据只存在本地。核心思路是 STM32 做采集和控制,WiFi 或 4G 模组做上行,物联网平台做数据存储和远程查看。下面按选型、硬件、固件、上云、避坑、进阶的顺序讲透,能照着复现。
2. 方案选型与硬件链路:为什么是 STM32 而不是树莓派
2.1 主控选型的三个现实约束
养殖场现场的第一个约束是供电和稳定性。棚里通常只有 220V 市电,电压波动大,夏天风机一启动就有干扰。STM32 这类 MCU 功耗低、没有操作系统、掉电重启后能立刻恢复采集,比跑 Linux 的板子更适合长期无人值守。第二个约束是成本,一个棚一套采集节点,主控加传感器加模组控制在百元级别,养殖场才愿意批量铺。第三个约束是实时性,氨气超标需要秒级触发本地声光报警,MCU 裸机或 RTOS 的响应确定性比应用层进程调度更可控。
常见做法是选 STM32F103 系列做入门,资源够用、资料多;如果要多路模拟量采集和更多串口,可以上 STM32F407。我一般会预留一个调试串口和一个模组串口,别把 UART 全占满,否则后期加屏或加 4G 会很被动。
2.2 传感器与执行器的搭配清单
| 监测项 | 常见传感器 | 接口 | 注意事项 |
|---|---|---|---|
| 温度湿度 | 数字温湿度传感器 | 单总线 | 远离热源和风机直吹位置 |
| 氨气 | 电化学氨气模块 | UART/模拟 | 需要预热,标定周期短 |
| 光照 | 光照强度模块 | I2C/模拟 | 避免被灯具直射 |
| 二氧化碳 | 红外 CO2 模块 | UART | 成本较高,按需选配 |
| 执行器 | 继电器组 | GPIO | 控制风机、加热、补光 |
氨气传感器是这套系统里最容易翻车的一环。电化学式模块上电后需要预热几分钟才稳定,直接拿刚上电的数据去判断会误报。另外它的输出会随温湿度漂移,如果只做单点标定,用几周后数值就偏了。稳妥做法是记录温湿度并做补偿,或者选带温度补偿的模块。
2.3 上行链路:WiFi 模组还是 4G 模组
棚区网络条件决定选型。如果场区有可用的 WiFi 覆盖,用 ESP8266 或 ESP32 做透传成本最低,AT 指令也简单。如果棚在偏远位置没有 WiFi,就得用 4G 模组,通过串口发 AT 指令拨号,再走 MQTT 上云。两者在固件层的差别主要是初始化流程和断线重连策略,业务逻辑可以共用一套。
提示:模组供电要单独走一路 LDO 或 DC-DC,别和传感器共用一条细线,模组发射瞬间的电流尖峰会把传感器读数拉偏。
3. 固件实现:从裸机采集到 MQTT 上云的完整链路
3.1 采集任务与数据滤波
先看采集部分。下面是一段简化的采集与滤波代码,跑在 STM32 上,用定时器触发周期采集,对模拟量做滑动平均,避免单次跳变触发误报。
// 采集周期 2s,对氨气模拟量做 8 点滑动平均 #define FILTER_LEN 8 static float nh3_buf[FILTER_LEN]; static uint8_t nh3_idx = 0; float nh3_filter(float raw) { nh3_buf[nh3_idx] = raw; nh3_idx = (nh3_idx + 1) % FILTER_LEN; float sum = 0; for (int i = 0; i < FILTER_LEN; i++) { sum += nh3_buf[i]; } return sum / FILTER_LEN; // 返回滤波后的氨气浓度 } void task_sample(void) { float t = sht_read_temp(); // 温湿度 float h = sht_read_humi(); float nh3 = nh3_filter(adc_read_nh3()); float lux = bh1750_read(); // 光照 // 本地阈值判断,超限立即驱动继电器和蜂鸣器 if (nh3 > NH3_ALARM || t > TEMP_ALARM) { gpio_set(RELAY_FAN, 1); gpio_set(BUZZER, 1); } pack_and_send(t, h, nh3, lux); // 打包后交给上行任务 }逻辑说明:nh3_filter用环形缓冲做滑动平均,长度 8 对应约 16 秒窗口,能压掉大部分尖峰又不至于让响应太迟钝。task_sample里先做本地判断再上传,这样即使网络断了,本地报警依然有效,这是养殖场场景的底线。参数上,NH3_ALARM和TEMP_ALARM要根据养殖品种设定,比如禽类对氨气更敏感,阈值要调低。
3.2 上行数据打包与 MQTT 连接
数据打包建议用轻量的 JSON,字段名短一点,省流量也省解析时间。下面是拼接和发布的示意。
// 拼接 JSON 并通过 MQTT 发布到平台 void pack_and_send(float t, float h, float nh3, float lux) { char payload[128]; snprintf(payload, sizeof(payload), "{\"t\":%.1f,\"h\":%.1f,\"nh3\":%.2f,\"lux\":%.0f}", t, h, nh3, lux); // topic 形如 /sys/{设备ID}/thing/event/property/post mqtt_publish(PROPERTY_TOPIC, payload, strlen(payload)); }逻辑说明:snprintf控制长度防止溢出,浮点保留位数按传感器精度来,温湿度一位小数、氨气两位、光照取整即可。PROPERTY_TOPIC是平台约定的属性上报主题,设备侧只需要按格式发,平台会自动解析成物模型属性。参数上要注意 MQTT 的 keepalive 和重连间隔,网络差的时候把 keepalive 设短一点能更快发现掉线,但太短会频繁重连,一般 60 秒起步。
3.3 断网缓存与补传
养殖场网络不稳定是常态,断网期间的数据不能直接丢。做法是在本地开一块环形缓冲区,把未确认发送的记录存起来,重连后按时间顺序补传。
// 简易环形缓存,存最近 200 条未发送记录 #define CACHE_MAX 200 static char cache[CACHE_MAX][128]; static uint16_t head = 0, tail = 0; void cache_push(const char *rec) { strncpy(cache[head], rec, 127); head = (head + 1) % CACHE_MAX; if (head == tail) tail = (tail + 1) % CACHE_MAX; // 覆盖最旧 } void cache_flush(void) { while (tail != head && mqtt_connected()) { mqtt_publish(PROPERTY_TOPIC, cache[tail], strlen(cache[tail])); tail = (tail + 1) % CACHE_MAX; } }逻辑说明:cache_push在每次采集后调用,cache_flush在 MQTT 连接成功后调用。缓冲区大小按断网时长和采集频率估算,2 秒一条、断网 10 分钟约 300 条,所以 200 条只够几分钟,实际项目里建议放到 500 条以上或改用外部 Flash。参数上要注意覆盖策略,满了之后覆盖最旧数据,保证最新数据一定在。
4. 上云对接:设备注册、物模型与数据流转
4.1 设备注册与三元组配置
在物联网平台上创建产品,定义好物模型属性,然后注册设备,拿到设备 ID、密钥等信息。这些信息烧进固件或存在外部 Flash 里,用于 MQTT 连接时的鉴权。常见做法是把三元组放在一个单独的配置区,方便批量生产时用工具写入,而不是每次改代码重编译。
连接流程一般是:模组初始化 → 拨号或连 WiFi → 建立 TCP → MQTT CONNECT(带 clientId、username、password)→ 订阅下发主题 → 周期上报属性。每一步都要有超时和重试,不能卡死在一个状态。
4.2 物模型属性与上报格式
物模型是平台理解设备数据的关键。把温度、湿度、氨气、光照定义成属性,指定类型和单位,平台才能正确存储和展示。上报时按属性名组织 JSON,平台解析后自动更新设备影子。如果字段名和物模型对不上,数据会进不来,这是新手最常踩的坑之一。
| 属性名 | 类型 | 单位 | 说明 |
|---|---|---|---|
| temperature | float | ℃ | 棚内温度 |
| humidity | float | % | 相对湿度 |
| nh3 | float | ppm | 氨气浓度 |
| lux | int | lx | 光照强度 |
4.3 云端规则与告警联动
数据上云后可以配置规则,比如氨气连续三次超过阈值就触发告警,推送到手机或短信。也可以在云端下发命令控制风机,但养殖场场景里本地控制优先级更高,云端命令只作为远程手动干预的补充。规则引擎的表达式要写清楚时间窗口和聚合方式,否则容易出现一超标就狂发告警的情况。
注意:云端下发命令和本地自动控制可能冲突,固件里要定义优先级,本地自动逻辑优先,云端命令只在手动模式下生效。
5. 避坑与排查:这套系统最容易出问题的五个地方
5.1 氨气读数一直偏高或漂移
现象:刚上电读数正常,运行几小时后数值缓慢升高,或者换一个棚读数差很多。原因:电化学传感器需要预热,且输出受温湿度影响,没有补偿就会漂移。解决:上电后先预热 3 到 5 分钟再采信数据,固件里加入温湿度补偿系数,并定期用标准气体或对比仪器标定。
5.2 MQTT 频繁掉线重连
现象:设备在线状态反复跳变,数据时有时无。原因:keepalive 设置过短、网络信号弱、模组供电不足导致重启。解决:keepalive 设到 60 秒以上,检查模组供电是否独立且足够,信号弱的地方加天线或改用 4G,固件里加重连退避,避免疯狂重连把模组拖死。
5.3 传感器读数被继电器干扰
现象:风机一启动,温湿度或氨气读数就跳一下。原因:继电器动作时产生电磁干扰,或者共用电源被拉低。解决:继电器线圈加续流二极管,传感器供电和继电器供电分开走,模拟量走线远离强电,软件上继续用滑动平均压尖峰。
5.4 数据上报了但平台看不到
现象:串口打印显示 MQTT 发布成功,但平台上设备属性不更新。原因:topic 写错、物模型属性名不匹配、JSON 格式不合法。解决:对照平台文档检查 topic 层级,确认属性名和物模型一致,用串口把 payload 打出来逐字核对,必要时先用平台提供的调试工具手动发一条验证。
5.5 断网后数据丢失
现象:网络恢复后,断网期间的数据查不到。原因:没有本地缓存,或者缓存被覆盖。解决:加环形缓冲区并扩大容量,重连后按顺序补传,补传时加时间戳,平台侧按时间入库。如果断网时间可能很长,改用外部 Flash 存,容量按小时级估算。
6. 进阶技巧:让这套系统真正能长期跑下去
先说一个验证方法。系统搭好后别急着交付,先做 72 小时连续运行测试,记录掉线次数、数据完整率、报警触发次数。我一般会写一个简单的统计脚本,把串口日志里的上报记录和平台侧数据做比对,算一下丢包率。如果丢包超过 1%,就要回头查网络和缓存策略,而不是安慰自己「差不多能用」。
再讲一个具体技巧:把阈值判断做成可配置的,存在 Flash 里,通过云端下发或本地按键修改,而不是写死在代码里。养殖场不同季节、不同品种的阈值不一样,写死意味着每次调整都要重新烧录,现场根本没法维护。下面是一个配置读取的示意。
// 阈值配置结构,存在 Flash 固定地址 typedef struct { float temp_alarm; float nh3_alarm; uint16_t sample_interval; } alarm_cfg_t; alarm_cfg_t cfg; void cfg_load(void) { flash_read(CFG_ADDR, &cfg, sizeof(cfg)); // 校验失败则加载默认值 if (cfg.sample_interval < 1 || cfg.sample_interval > 60) { cfg.temp_alarm = 32.0f; cfg.nh3_alarm = 20.0f; cfg.sample_interval = 2; } }逻辑说明:cfg_load在启动时读取配置,做范围校验,异常时回落到默认值,避免 Flash 损坏导致系统跑飞。参数上,sample_interval限制在 1 到 60 秒之间,太短费流量,太长漏掉突发变化。
还有一个容易被忽略的点是设备时间。上报数据带时间戳能让平台侧排序和追溯,但 STM32 本身没有 RTC 的话,重启后时间就乱了。常见做法是加一颗 RTC 芯片配纽扣电池,或者每次连上平台后通过时间同步接口校准。没有准确时间戳,断网补传的数据在平台上就是一堆乱序记录,排查问题时非常痛苦。
最后说一个我自己的习惯:每套设备出厂前,把固件版本、传感器批次、标定日期写进 Flash 的一个信息区,现场出问题时先读这个区,能快速判断是硬件批次问题还是软件问题。这个习惯帮我省过很多次来回跑现场的油钱。养殖场环境监测这方向值不值得做?如果目标是低成本、可批量、能长期无人值守,STM32 加物联网平台的组合目前依然是性价比很高的选择,难点不在写代码,而在现场细节和长期稳定性。希望帮到你。
本文还有配套的精品资源,点击获取