做仓库环境控制这套东西,最早是因为朋友那边一个存放电子元器件的周转仓出了问题。南方的回南天,湿度能直接干到90%以上,包装纸箱软化、IC引脚氧化,再加上进出货带起来的粉尘,环境堪称灾难。市面上成品环境监控设备不是没有,但价格高、数据封闭、控制逻辑固化,想跟自己的风机和除湿机联动非常费劲。所以干脆用STM32自己做了这套系统:温湿度加粉尘监测,自动通风除湿,ESP8266上云,手机端随时看数据、远程开关设备。前前后后改了三个版本,稳定跑了好几个月,这里把设计和踩坑过程完整写下来,给同样想自建环境控制系统的人一个参考。
1. 系统设计思路与方案拆解
1.1 仓库环境监测到底要监测什么
仓库环境不像机房里那么苛刻,但核心指标就三个:温度、湿度、粉尘浓度。温度影响电子元器件老化速度和化学材料的稳定性,湿度影响霉变、氧化、受潮,粉尘浓度影响空气质量、静电吸附和除尘设备的工作效果。
设计之前得先定监测范围,不能盲目参考气象数据。电子元件仓一般建议温度15~30摄氏度,相对湿度40%~70%,粉尘浓度按工业场所卫生标准控制在4mg/m³以内比较合适。这个区间决定了传感器选型和阈值设定,后面所有控制逻辑都围绕这几个数字展开。
另外要注意采样频率问题。仓储环境变化慢,不需要像工业现场那样高频采样,温湿度5秒一次、粉尘10秒一次完全够用。频率太高反而增加传感器老化速度和云平台流量消耗,没实际意义。
监测数据不是只拿来显示的,真正核心是把采集值变成控制动作。温湿度超标开风机、湿度大开除湿机、粉尘浓度超限加强排风,这些逻辑如果靠人工巡检根本忙不过来,尤其夜间更容易出问题。所以系统必须有过硬的本机自动控制能力,而不是单纯“上传数据”。
1.2 为什么用STM32+ESP8266这套组合
方案选型时几个常见路线对比过。用纯Wi-Fi模块加传感器直接上报,比如ESP8266裸跑,代码写起来简单,但弱项是模拟量采集精度一般、ADC通道有限、多路控制逻辑写起来比较拧巴。用PLC成本高出几个量级,而且这种小型自建项目没必要。用树莓派性能过剩,功耗高,还需要保证稳定运行,仓库环境不一定合适。
最终用STM32F103C8T6做主控加ESP8266做通信,原因很实际。STM32负责所有传感器的采集和控制逻辑,实时性和稳定性有保障,即使网络断了也能独立运行;ESP8266只干一件事,就是透传数据到云平台,职责单一,出问题好排查。两个芯片各管一摊,互不拖累,调试起来非常清爽。
还有个隐形优势是功耗和成本。整套硬件成本可以压在60元以内(不含风机和除湿机),长期通电的功耗也就几瓦。仓库环境通常没有专业机房供电,普通220V插座加一个5V电源模块就能带起来。
如果以后要扩展更多的传感器或者换更强的主控,STM32的引脚余量和外设资源也比较充裕。比如加烟雾传感器、水浸传感器、门磁开关,或者把ESP8266替换成4G模块,都不需要推翻整个硬件架构。
1.3 自动通风除湿的控制闭环
自动化控制的核心就是闭环,说白了就是“测量-判断-执行-再测量”。这套系统里,温湿度传感器每5秒采集一次数据,粉尘传感器每10秒采集一次,数据经过滤波处理后进入状态判断逻辑。判断结果决定继电器是否动作,控制风机、除湿机或加热器的启停。
闭环里最关键的不是“超阈值就开”,而是“回差控制”。比如湿度超过70%开除湿机,那湿度降到多少才关?如果还是70%,就会出现在临界点反复吸合继电器的问题,设备寿命折损严重。我设的规则是湿度高于75%启动除湿,低于65%停止,中间留10%的回差区间,避免频繁切换。温度控制类似,温度高于30度开启通风,低于26度关闭,道理是一样的。
控制逻辑还有一个重要动作是优先级管理。除湿机工作时会产生热量,如果温度同时超标,排风系统必须优先启动,否则仓库内会越来越热。粉尘超限也需要立即加大排风量,甚至关断回风。逻辑层面用状态机处理,比单纯if嵌套要好维护得多,后面代码部分细说。
2. 硬件选型与核心接线要点
2.1 主控、传感器与通信模块选型
主控选择STM32F103C8T6,蓝色Pill板或者自己画板都可以。原因不多说了,资源够用、资料多、烧录方便。要注意的是市面上有很多翻新片,采购时尽量选正规渠道,不然调试到一半芯片发热烧录失败,很难判断是硬件还是代码问题。
温湿度传感器我试过DHT22和AHT20两种,最终在量产版选了AHT20。DHT22精度不错,但单总线时序对代码实时性要求高,稍微被中断打扰就读不出数据。AHT20走I2C接口,数据线只有两根,性能稳定,精度正负0.3摄氏度、正负2%RH,完全满足仓库监测需求。如果手里只有DHT22,按后文DHT22的读取方式写也能用,这里两种方案都会讲到。
粉尘传感器用的是夏普GP2Y1010AU0F,这是最常用的光学灰尘传感器,原理是红外LED照射空气中的颗粒物,光敏元件接收反射光,输出模拟电压与粉尘浓度成正比。参数上灵敏度约0.5V/(0.1mg/m³),输出电压零点大概0.5~0.6V。它的数据接口很简单,就是一根模拟输出引脚,接到STM32的ADC引脚上就行。
ESP8266用的是ESP-12F模块,比ESP-01多了天线和充足的Flash,信号稳定。刷好AT固件后,通过串口与STM32通信,波特率115200。很多人纠结用AT指令还是直接二次开发,我建议用AT,把通信协议放在AT指令层,STM32代码简单,而且模块挂了可以单独换一个,不用重新烧固件。
2.2 核心接线与引脚分配
画电路板之前先列了一个引脚分配表,把所有外设占用的引脚定死,避免后续写代码时发现冲突。每个外设的电源也需要单独规划,传感器和ESP8266不能共用同一个LDO的大电流路径,否则Wi-Fi发射瞬间压降会导致ADC读数跳动。
下面是实际使用的引脚分配表:
| 外设接口 | STM32引脚 | 说明 |
|---|---|---|
| AHT20温湿度传感器 | PB8 (SCL), PB9 (SDA) | I2C1,上拉4.7k |
| GP2Y1010AU0F粉尘传感器 | PA1 (ADC1_IN1) | 模拟电压输入,0~3.3V |
| ESP8266 UART | PA9 (USART1_TX), PA10 (USART1_RX) | 波特率115200 |
| 继电器1(风机) | PB0 | 高电平触发,接ULN2003 |
| 继电器2(除湿机) | PB1 | 高电平触发,接ULN2003 |
| 继电器3(加热器) | PB10 | 高电平触发,接ULN2003 |
| 本地按键 | PB12, PB13, PB14 | 手动模式/阈值调整 |
| 状态LED | PB5 | 运行指示灯 |
GP2Y1010AU0F的接法有个细节需要注意。模块上除了VCC、GND、V0(模拟输出)之外,还有LED驱动引脚,需要接一个150欧姆电阻到VCC,同时用电容保证LED供电的稳定性。如果直接把LED引脚接5V而不加电阻,传感器内部的红外LED很容易过流老化。另外这个传感器的模拟输出是脉冲式的,不是持续电平,ADC采样时最好踩着它的时序来采样,否则读数漂移会很大。
ESP8266的供电是另一个坑。它的峰值电流能到300mA以上,用STM32板载3.3V LDO大概率供电不足,表现就是AT指令偶发无响应、连接Wi-Fi时重启。我单独用了一颗AMS1117-3.3从5V取电给ESP8266供电,并且在模块附近加了470uF电解电容和100nF陶瓷电容。实测下来稳定很多。
2.3 继电器驱动与负载保护
继电器我用的是5V低电平触发的型号,但这里有个概念容易弄混。低电平触发指的是模块输入端低电平时继电器吸合,不是指控制信号用低电平驱动。STM32的GPIO驱动能力不够直接推继电器,中间加了ULN2003达林顿管阵列,安全又简单。
负载侧如果是感性负载,比如排风机、空调压缩机这类电机,断电瞬间会产生反向电动势,容易损坏继电器触点甚至干扰MCU。处理办法有三个:继电器触点两端并联RC吸收电路,阻容值典型为100欧姆加0.1uF;或者并联一个压敏电阻;或者直接用固态继电器隔离。我在风机和除湿机上都加了RC吸收,配合压敏电阻,基本没有跳闸或者干扰重启的情况。
控制大功率设备时还必须考虑电气隔离。强电部分和弱电部分不能共地,继电器模块的光耦负责隔离,控制信号侧和负载侧完全分离开,安全性才有保障。裸板调试时如果没有光耦隔离,万一手上静电或者误触碰到负载线,后果很严重。
3. 核心代码实现与关键逻辑
3.1 温湿度采集:I2C方式与DHT22兼容写法
AHT20的读取比较简单,初始化后发送触发测量命令,等待大约80毫秒,然后读取6个字节数据,按规定位解析出温度和湿度。这里贴一段实际用的核心函数,可以直接抄:
// AHT20读取温湿度 uint8_t AHT20_TriggerMeasure(void) { uint8_t buf[3] = {0xAC, 0x33, 0x00}; return HAL_I2C_Master_Transmit(&hi2c1, 0x70, buf, 3, 100); } _Bool AHT20_ReadData(float *temp, float *humid) { uint8_t buf[6] = {0}; HAL_I2C_Master_Receive(&hi2c1, 0x71, buf, 6, 100); uint32_t raw_humi = ((buf[1] << 12) | (buf[2] << 4) | (buf[3] >> 4)); uint32_t raw_temp = (((buf[3] & 0x0F) << 16) | (buf[4] << 8) | buf[5]); *humid = (float)raw_humi * 100.0f / (1 << 20); *temp = (float)raw_temp * 200.0f / (1 << 20) - 50.0f; return (buf[0] & 0x80) ? false : true; // bit7表示忙 }如果用的是DHT22,就要注意单总线时序。DHT22数据线接PB7,配置为开漏输出带上拉电阻。读取时序大概是:主机拉低总线至少1ms,然后释放,传感器响应后拉低80us,再拉高80us,之后按bit流输出40位数据。每一位的起始是50us低电平,后续高电平时间26~28us代表0,70us代表1。高电平脉宽用定时器输入捕获或者延时轮询测量,精度控制在±2us以内。
DHT22最怕中断干扰,如果系统里同时跑ESP8266串口中断和ADC采集,建议在读取DHT22的整个时序过程中关闭全局中断,不然极易读到错误的校验值。DHT22的校验算法是前四个字节相加取低8位等于第五个字节,校验不过的帧直接丢弃,不参与控制逻辑。
3.2 粉尘浓度采集与滤波算法
GP2Y1010AU0F输出的是模拟电压,可以用ADC1的规则通道连续采样。但这传感器有个特点,内部LED是脉冲驱动的,输出电压在LED亮起后才稳定,所以正确做法是:用PWM控制LED引脚进行脉冲驱动,同时在脉冲稳定窗口内去采样V0。
简化做法也可以用外部定时器触发,定时器产生脉冲同时启动ADC采样,具体代码如下:
// 粉尘采样,取8次平均值 float Dust_ReadOnce(void) { // 启动50us LED脉冲后,在280us处采样 HAL_GPIO_WritePin(LED_CTRL_GPIO_Port, LED_CTRL_Pin, GPIO_PIN_SET); delay_us(280); HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 10); uint16_t adc = HAL_ADC_GetValue(&hadc1); HAL_GPIO_WritePin(LED_CTRL_GPIO_Port, LED_CTRL_Pin, GPIO_PIN_RESET); return adc * 3.3f / 4096.0f; } float Dust_ReadFiltered(void) { float sum = 0; for (int i = 0; i < 8; i++) { sum += Dust_ReadOnce(); delay_ms(20); } float avg_v = sum / 8.0f; // 根据典型灵敏度换算 mg/m3 // V0是零点电压,按实际标定值填写 const float V0 = 0.6f; const float K = 0.1f / 0.5f; // 每0.5V对应0.1mg/m3 float dust = (avg_v - V0) * K; if (dust < 0) dust = 0; return dust; }这个传感器有个必须知道的特性:LED持续点亮时间不能太长,否则温漂明显。我控制在每个采样周期内LED只点亮不到300us,然后关闭至少20ms。另外粉尘传感器的零点电压每块板子都不一样,装配后要先用干净空气标定一次,把实际测得的无尘电压替换掉V0,否则浓度值永远都是偏的。
滤波算法上我用了8次滑动平均,效果已经不错。如果还想更平滑,可以再加一阶低通滤波,系数取0.3即可。注意不要把滤波系数取得太小,粉尘浓度本来就是动态变化的,过度滤波会让实时性变差,自动排风系统反应迟钝。
3.3 控制逻辑与状态机实现
控制逻辑用状态机实现,每个设备有三个状态:待机、延迟启动、运行中。整体是一个每秒运行一次的任务函数,读取滤波后的温湿度和粉尘值,然后判断状态迁移。
typedef struct { uint8_t state; // 0待机 1运行 uint16_t delay_cnt; // 防抖延时计数 float start_th; // 启动阈值 float stop_th; // 停止阈值 } DeviceCtrl; void Env_ControlTask(void) { EnvData env = GetLatestEnvData(); // 风机:温度高或粉尘高时启动,温度和粉尘都恢复后停止 ControlDevice(&fan, env.temp > 30.0f || env.dust > 4.0f, env.temp < 26.0f && env.dust < 2.0f); // 除湿机:湿度高启动,降到回差下限停止 ControlDevice(&dehumidifier, env.humi > 75.0f, env.humi < 65.0f); // 加热器:温度过低启动,升温后停止 ControlDevice(&heater, env.temp < 5.0f, env.temp > 10.0f); }ControlDevice里面做防抖判断:启动条件满足后,连续3秒仍然满足才真正启动,停止条件也一样,连续3秒满足才停止。这个看起来多余的设计,实际使用中救了大命。仓库门一开一关,几秒钟内数据起伏很大,没有防抖的话风机就会跟着来回启停。
状态机的优先级在代码里通过调用顺序和互斥条件保证。比如除湿机运行时会产热,如果此时温度高于31度,强制停止除湿机,开启风机排风,等温度回落后再恢复除湿。加热器和风机同理,不会出现加热和制冷同时开启的矛盾状态。
本地控制面板我用三个按键设置阈值,通过OLED显示当前参数。OLED显示不是必须的,但调试时非常方便,不用每次改阈值都重新烧写程序或者打开串口。
3.4 ESP8266 AT指令上云流程
ESP8266的通信协议是标准AT指令,STM32用USART1发送字符串,模块返回结果。这里先说明模块上电后必须等待至少1~2秒,等它打印ready或者能响应AT指令后再操作,否则第一条AT指令会丢失。
连接云平台之前要先把ESP8266配置成Station模式并连接路由器:
AT+CWMODE=1 AT+CWJAP="仓库WiFi名","仓库密码"连接Wi-Fi后,如果云平台走TCP透传,可以用下面这套指令:
AT+CIPSTART="TCP","183.230.40.39",80 AT+CIPMODE=1 AT+CIPSEND执行AT+CIPSEND之后,模块进入透传模式,所有发送到串口的数据都会原样送向服务器。要退出透传发送+++,注意前后不能带回车换行。
如果是走MQTT协议,部分固件支持AT+MQTTCONN系列指令,不支持的固件就需要用TCP方式自己拼接MQTT报文,或者改用串口转Wi-Fi的模块直接对接MQTT Broker。我这里用的是普通TCP透传加HTTP接口上报,逻辑更简单:数据攒成JSON字符串,POST到云平台接口,服务器返回200即表示成功。
实际开发中不要把上报频率设太高。我设置30秒上报一次温湿度、粉尘数据和设备状态,流量开销很小,免费版云平台额度完全够用。如果设成几秒一次,一是ESP8266长时间高负载容易发热不稳定,二是云平台API可能有频率限制。
3.5 断网降级与本地可靠性保障
环境控制系统最怕的不是断网,而是网络异常后控制逻辑失灵。设计铁律:云平台只是“看”和“远程控制”,本机自动控制绝不依赖网络。所有传感器采集、阈值判断、继电器控制全部在STM32本地完成,ESP8266挂了不影响自动控制功能。
断网检测我用了一个简单方法:STM32每30秒发送一次心跳到云平台,如果连续三次没有收到服务器响应,就认为网络异常。此时系统切换到“本地降级模式”,OLED上显示网络异常图标,但仍然正常显示数据和控制设备。云平台的按钮下发命令在断网时不生效,等网络恢复后自动切回远程模式。
实现上ESP8266和STM32的串口通信加了一个简单的分包协议,以起始符和结束符界定一帧数据,避免AT指令返回内容与数据上报混在一起解析出错。比如上报帧格式:{ "type":"report", "temp":25.3, "humi":62.1, "dust":3.2 },以@@开头,##结尾,接收端按帧解析。
4. 上云平台接入与远程联动
4.1 数据格式与字段设计
上云不只是把温湿度数值发上去,要考虑数据结构化和后续展示的便利性。我定义的数据帧包括温度、湿度、粉尘浓度、风机状态、除湿机状态、加热器状态六项,外加设备ID,方便多套系统共用同一个云平台。
实际JSON报文长这样:
{ "deviceId": "WH_CTRL_01", "temp": 26.8, "humi": 73.2, "dust": 2.7, "fan": 1, "dehum": 0, "heat": 0, "ts": 1687856245 }ts字段用Unix时间戳,方便云平台排序和图表统计。设备ID用字符串而不是纯数字,方便以后接入不同类型设备时区分。
上报周期30秒一次。如果要看趋势曲线,30秒的采样密度已经足够画出一整天的平滑曲线。控制状态如果发生变化,比如风机启动,可以立刻补发一帧,这样APP上的设备状态响应不会滞后太久。
4.2 云平台选择与设备接入
我用过OneNET和巴法云,也试过阿里云物联网平台。选型标准只有三条:免费额度够不够、设备接入文档全不全、API是否稳定。
OneNET的旧版MQTT接口已经逐步下线,现在主推新版物联网开放平台,不太建议新项目继续用。巴法云接入简单,MQTT地址bemfa.com,端口9501,以Topic区分设备,免费额度对个人项目足够。阿里云物联网平台功能最强,但产品模型、Topic定义、设备证书这些概念对新手不太友好,周期长。
ESP8266通过MQTT连巴法云的AT流程大致如下:
AT+CWMODE=1 AT+CWJAP="WiFi名","WiFi密码" AT+MQTTUSERCFG=0,1,"设备名","","" AT+MQTTCONN=0,"bemfa.com",9501,1 AT+MQTTSUB=0,"主题名",1 AT+MQTTPUB=0,"主题名","{\"temp\":26.8}",1MQTT的好处是有主题订阅功能,双向通信方便。STM32不但能上报,还能订阅控制Topic,云平台下发命令时ESP8266会收到消息,再转发给STM32。
云平台如果只做数据展示,用HTTP协议反而更省事。数据直接POST到平台提供的接口,不用维护长连接,省电也省心。我实际开发中先用HTTP把核心数据跑通,后续需要远程控制时再改MQTT双通道。
4.3 远程告警与远程控制
告警规则我放在云端,也可以在设备端做。设备端告警的好处是断网也能响铃,云端告警的好处是可以联动短信、APP推送和电话通知。我这套系统两个都做了:本地超过阈值时蜂鸣器响,云端超过阈值时通过云平台的规则引擎触发APP推送。
云端规则设置参考:温度大于31度或小于8度,湿度大于80%,粉尘大于5mg/m³,任一条件持续两分钟以上就触发报警。这里的“持续两分钟”很重要,避免瞬时波动造成误报。
远程控制通过MQTT下行Topic实现。云平台往控制Topic发一条JSON指令,比如{"cmd":"fan_on"},ESP8266收到后通过串口转发给STM32,STM32解析指令并控制继电器。控制指令与本地自动控制有优先级逻辑:手动指令执行后,30分钟内自动控制不会覆盖,时间到了恢复自动模式。这个设计是为了避免远程开排风后,自动逻辑下一秒又把风机关了。
4.4 设备安全与稳定性
物联网设备最大的隐患是网络安全。ESP8266直连公网MQTT Broker,必须做好访问控制。具体做到三点:第一,MQTT用户名和密码不能使用默认值,密码不要用纯数字;第二,上报Topic和订阅Topic分开,订阅下行控制Topic的权限尽量收紧;第三,固件里不要硬编码云平台密钥,我虽然也是硬编码的,但至少穿了一层简单加密壳,防止固件被直接读取。
连接稳定性上,ESP8266长时间运行后偶尔会掉线,解决方法是在STM32侧做定时检测:如果连续5分钟没有收到MQTT心跳返回,就重启ESP8266模块,重新连接。实测这种“看门狗加自动复位”策略比单纯依赖AT指令重连可靠得多。
5. 实际调试中踩过的坑
5.1 粉尘传感器数据异常
刚组装完第一版时,粉尘浓度读数一直是0.8mg/m³左右,比正常值高不少。排查后发现是传感器的LED控制引脚悬空没配置,导致红外LED不受控,光敏元件接收到恒定反射光。处理好引脚初始化后,数值马上恢复正常。
后来还有一次数据突然跳变到几十mg/m³,查了半天发现是排风扇开启时的震动带动传感器轻微位移,光路被遮挡。重新固定传感器并加了一层海绵减震后解决。粉尘传感器对物理位置非常敏感,不要在它旁边直接安装大功率继电器,继电器吸合瞬间产生的震动和电磁干扰都会影响读数。
5.2 DHT22时序频繁读取失败
最开始我用DHT22,代码从网上下载的例程改了一下,单独测试一切正常,跟ESP8266并机后每几分钟就报一次超时。原因是ESP8266的天线辐射干扰导致单总线上的信号波形畸变,加上DHT22对时序要求严苛,稍有偏差就读不出起始信号。
解决思路是给DHT22的数据线串联一个300欧姆电阻,并在传感器电源引脚加10uF电解电容和100nF陶瓷电容。如果还有问题,就在读取数据期间关闭USART1中断和SysTick中断,用查询方式读取。不过从体验上看,AHT20在抗干扰方面强太多,这也是我后来放弃DHT22的重要原因。
5.3 ESP8266供电不足导致AT无响应
上电后发AT没反应,串口助手一直空白,这种问题八成不是代码而是供电。ESP8266连Wi-Fi瞬间电流很大,用STM32板载3.3V供电电压会跌到2.7V以下,模块直接重启或者收发异常。用万用表测模块VCC引脚电压,如果启动时低于3.0V,基本就是供电问题。
解决办法前面说了,独立LDO供电外加电容。还有更简单的思路:用5V电源模块,然后通过两路稳压分别给STM32和ESP8266供电,地线一定要共地,否则串口通信电平不一致,乱码概率很高。
5.4 恢复出厂设置后AT指令卡死
有一次我把ESP8266执行了AT+RESTORE,然后立刻在循环里发AT等待“OK”,结果程序死循环,模块始终不回应。后来才明白,AT+RESTORE之后模块不是马上恢复,而是要重新初始化文件系统和参数,期间串口不会响应任何AT指令。必须等它重启完成,或者干脆上电后先延时3秒再操作。
正确的处理方式是:执行AT+RESTORE,等待5秒以上,再发送AT测试。用代码实现时,重启后第一次AT指令要带重试机制,连续失败三次再重启模块,不要卡在一个循环里。
5.5 继电器频繁吸合与触点打火
设备刚上电时风机和除湿机出现了快速反复吸合的问题,大概每3秒切换一次,继电器触点火花明显。原因是阈值判断里没有加回差和防抖逻辑。
在代码里加了启动/停止延时之后,这个问题彻底消失。另外给继电器控制引脚增加了RC滤波,防止GPIO在MCU启动瞬间误输出高电平,把设备误开起来。STM32复位瞬间IO口默认是浮空输入或低电平,但也有些模块因为上电时序问题会瞬态闪一下,对继电器来说非常伤,加RC滤波是最省事的缓解方案。
5.6 ADC数据受Wi-Fi模块干扰
ESP8266在发送数据时,电流波动会让电源产生毛刺,ADC读数跟着跳。测温湿度还好,粉尘数据跳得明显。我的处理方法有三个层面:硬件上在粉尘传感器供电端加LC滤波,ADC参考电压用专门的基准源;软件上粉尘采样避开ESP8266发送窗口,比如ESP8266发送后的50ms内不启动ADC;最后再用前文提到的滑动平均,三重过滤下来数据非常稳定。
5.7 STM32烧录失败与启动配置
STM32F103C8T6烧录失败最常见的原因是BOOT0引脚状态不对。正常情况下BOOT0接10k下拉到GND,从Flash启动。如果BOOT0悬空或者被拉高,板子会进入串口下载模式,按复位键也用不了调试器。
另外用ST-Link调试时,SWDIO和SWCLK两个引脚如果和继电器控制引脚复用,一定要在初始化GPIO时避免配置冲突。若代码里把SWDIO引脚重映射成普通GPIO,第二次烧录时就只能按住复位键烧录或者用串口ISP擦除,这个坑我踩过一次,教训深刻。
6. 系统成本、扩展方向与总结
整套系统硬件成本明细大致如下:STM32F103C8T6核心板约10元,AHT20传感器模块约5元,GP2Y1010AU0F粉尘传感器模块约20元,ESP8266 ESP-12F模块约8元,继电器模块约8元,OLED屏约7元,电源模块及其他杂项约10元。加起来不含外壳和终端设备,在70元以内。批量做板子后成本可以压到50元以下。
后续扩展方向有几个。一是加入烟雾传感器和水浸传感器,仓库安全不仅靠温湿度,防水防火更关键。二是把ESP8266升级成4G Cat.1模块,摆脱仓库路由器依赖,农村或者偏远仓库也能远程监控。三是增加云端的AI规则分析,比如根据历史数据预测湿度趋势,提前启动除湿机,而不是等到超标才动作。
我个人在实际操作中最深的一点体会是:做这类系统,一定要把“本地自动控制”的可靠性放在“上云”前面。刚开始我也沉迷于手机APP显示和远程控制的炫酷感,后来有一次ESP8266掉线,发现本地控制依然稳稳工作,才真正意识到这种分层设计有多重要。网络永远是不可靠的,传感器会漂移,继电器会老化,但一套设计良好的状态机加上合理的回差逻辑,能在绝大多数情况下保证设备安全运行。
另外一个经验是:调试环境控制项目,先别急着写代码,拿一块万用表、一个串口调试助手,把传感器、无线模块、继电器逐项点亮,确认每个环节的电平、时序、供电没有问题,再开始拼系统。我前两个版本的Bug,一半以上是硬件连接和供电问题,真正核心逻辑反而没花太多时间。先把这套系统的每一个环节摸透,后续加功能、换平台、改阈值都只是水到渠成的事。