1. 项目概述:当STM32遇上环境监测
去年帮本地一家小型温室大棚部署环境监测系统时,我深刻体会到传统人工记录温湿度的低效。这套基于STM32和OneNet平台的环境检测系统,正是为解决这类痛点而生。它通过STM32F103C8T6作为主控,搭配DHT11温湿度传感器和MQ-135空气质量传感器,将实时数据上传至OneNet物联网平台,实现环境参数的远程监控和异常预警。
这个系统的核心价值在于其部署灵活性和成本优势。相比动辄上万的商业环境监测设备,整套硬件成本可以控制在200元以内,特别适合中小型农业大棚、实验室、仓库等场景。我曾用三个这样的节点覆盖了一个800平米的蘑菇种植房,通过手机就能随时查看各区域的微气候差异。
2. 硬件设计解析
2.1 主控芯片选型考量
选择STM32F103C8T6(蓝桥杯开发板常用型号)主要基于三点考虑:
- 72MHz主频足够处理传感器数据并运行轻量级协议栈
- 内置的64KB Flash和20KB SRAM满足程序存储需求
- 丰富的GPIO和USART接口便于扩展其他传感器
实际使用中发现,这款芯片的ADC精度(12位)对气体传感器信号采集完全够用。有个细节要注意:PCB设计时最好给VDDA和VSSA引脚加上LC滤波,我在初期版本没做这个处理,导致ADC读数有约5%的波动。
2.2 传感器模块搭配技巧
DHT11温湿度传感器:
- 成本约8元,精度±2℃/±5%RH
- 单总线协议节省IO口资源
- 注意:上电后需要1s稳定时间才能读取有效数据
MQ-135空气质量传感器:
- 检测NH3、NOx、苯系物等有害气体
- 需要预热5分钟后数据才稳定
- 建议每30天进行一次24小时通电老化校准
传感器布局有个实用经验:把DHT11放在远离MCU的位置,因为STM32运行时产生的热量会影响温度测量。我在PCB上专门做了个延伸支架,让传感器距离主控至少5cm。
3. 嵌入式软件设计
3.1 传感器驱动开发
DHT11的驱动时序要求严格,这里分享一个稳定的读取函数:
c复制#define DHT11_PORT GPIOB
#define DHT11_PIN GPIO_PIN_9
uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi) {
uint8_t buf[5] = {0};
// 主机拉低18ms后拉高20-40us
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
delay_ms(18);
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
delay_us(30);
// 等待从机响应
if(DHT11_Check_Response() == ERROR) return ERROR;
// 读取40位数据
for(int i=0; i<5; i++) {
buf[i] = DHT11_Read_Byte();
}
// 校验和验证
if(buf[4] != (buf[0]+buf[1]+buf[2]+buf[3]))
return ERROR;
*humi = buf[0];
*temp = buf[2];
return SUCCESS;
}
关键点:STM32的GPIO速度要配置为最高速模式,否则可能因响应不及时导致读取失败。
3.2 OneNet协议对接实战
使用EDP协议上传数据的核心流程:
- 建立TCP连接:OneNet服务器地址为183.230.40.39:876
- 发送鉴权报文(需包含设备ID和API_KEY)
- 按固定格式打包传感器数据
- 维持心跳(建议间隔60秒)
一个典型的数据包构造示例:
c复制void build_edp_packet(char *buf, float temp, float humi, int air) {
char json[128];
sprintf(json, "{\"temp\":%.1f,\"humi\":%.1f,\"air\":%d}",
temp, humi, air);
int json_len = strlen(json);
int pkg_len = 12 + json_len; // EDP头固定12字节
// 构造EDP包头
buf[0] = 0x80; // 类型:数据上报
buf[1] = (pkg_len >> 8) & 0xFF;
buf[2] = pkg_len & 0xFF;
// 添加数据流名称
strcpy(buf+3, "env_data");
buf[11] = json_len >> 8;
buf[12] = json_len & 0xFF;
// 填充JSON数据
memcpy(buf+13, json, json_len);
}
4. 云端平台配置要点
4.1 OneNet数据流管理
在OneNet控制台创建数据流时,建议采用这样的命名规范:
- 温度:temp(单位℃)
- 湿度:humi(单位%RH)
- 空气质量:air_q(单位ppm)
创建触发器时,我通常会设置两级报警:
- 初级预警:温度超过28℃或湿度低于40%
- 紧急报警:温度超过32℃或CO2浓度>1000ppm
4.2 移动端监控方案
利用OneNet提供的HTTP API,可以快速开发微信小程序:
javascript复制// 获取设备最新数据
function getDeviceData(deviceId) {
return new Promise((resolve, reject) => {
wx.request({
url: `https://api.heclouds.com/devices/${deviceId}/datapoints`,
header: {
'api-key': 'your_api_key_here'
},
success(res) {
if(res.data.errno === 0) {
resolve(res.data.data);
} else {
reject(res.data.error);
}
}
})
});
}
一个小技巧:在数据展示页面添加"刷新"按钮的同时,建议实现下拉刷新功能,因为很多农业用户习惯这种操作方式。
5. 系统优化与问题排查
5.1 低功耗设计实践
要使设备持续工作于电池供电模式,需做以下优化:
- 修改STM32时钟配置为HSI模式(省去外部晶振功耗)
- 设置采集间隔为5分钟(DHT11长期通电会影响寿命)
- 采用间断式网络连接:
- 每次采集后唤醒ESP8266
- 数据上传完成后立即进入深度睡眠
实测表明,采用2000mAh锂电池可维持约45天运行。
5.2 常见故障处理手册
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 数据上传失败 | SIM卡欠费/网络信号弱 | 检查AT+CSQ信号强度(应>10) |
| 温度读数异常 | DHT11接触不良 | 重新插拔传感器,检查上拉电阻 |
| 平台显示离线 | 心跳包未及时发送 | 检查看门狗配置和网络延迟 |
| 数据跳变严重 | 电源干扰 | 在MCU和传感器电源间加100μF电容 |
遇到最棘手的问题是一次集体掉线事件,后来发现是运营商NTP服务器同步导致的时间戳混乱。解决方法是在代码中添加本地RTC备份时钟:
c复制void RTC_Backup_Init(void) {
__HAL_RCC_BKP_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
if(BKP->DR1 != 0xA5A5) {
// 首次运行需要配置RTC
RTC_Init();
BKP->DR1 = 0xA5A5;
}
}
6. 项目扩展方向
这套基础系统可以衍生出多个实用变种:
- 温室自动控制系统:增加继电器模块,当温度超标时自动开启通风设备
- 多节点组网方案:通过LoRa模块实现半径3km内的传感器网络
- 数据本地存储:添加SPI Flash芯片,在网络中断时缓存数据
最近正在试验一个有趣的应用:在蜂箱中部署该系统,通过分析温湿度变化预测蜂蜜产量。初步数据显示,当箱内湿度持续低于40%时,蜜蜂活动会明显减少。