ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于STM32与ESP8266的仓库环境监测系统设计与实现

基于STM32与ESP8266的仓库环境监测系统设计与实现 1. 项目缘起与整体设计思路仓库环境管理这件事没做过的人觉得不就是测个温湿度嘛一个几十块钱的成品传感器就能搞定。但真在电子制造车间或者物料仓储现场待过就知道事情远没有这么简单。我接手这个项目的起因很朴素一个做SMT贴片加工的朋友找到我说他们车间里有一批锡膏和MSD潮湿敏感器件因为仓库湿度偶尔飙到70%RH以上导致过炉后虚焊、立碑的比例明显上升一批板子返修成本好几万。他们之前用的是一台壁挂式除湿机靠人每天早晚各看一次墙上的温湿度计手动开关。这种模式的问题很明显——人总有疏忽的时候夜里湿度上来了没人管第二天早上才发现损失已经造成了。所以这个项目的核心目标就一句话让仓库自己感知环境、自己判断、自己动作同时把数据传到远端手机上随时能看。具体拆下来是四件事第一用STM32做主控采集温湿度和粉尘浓度第二根据阈值自动控制通风风机和除湿设备第三通过ESP8266把数据上传到云平台第四本地要有屏幕显示和声光报警方便现场人员第一时间知道异常。为什么选STM32而不是直接用ESP32或者Arduino这是很多人问我的第一个问题。ESP32确实自带WiFi一颗芯片就能搞定采集和联网看起来更省事。但在这个项目里我坚持用STM32ESP8266的双芯片方案理由有三点。一是工业现场的稳定性STM32的定时器、ADC、中断响应这些底层资源非常成熟跑裸机或者FreeRTOS都很稳不会因为WiFi协议栈的调度影响到传感器采集的实时性。二是分工清晰STM32专心做采集和控制逻辑ESP8266专心做网络通信两者通过串口AT指令交互任何一方出问题都好排查。三是成本可控STM32F103C8T6这颗芯片价格便宜、资料丰富ESP8266-01S模块也就几块钱整体BOM成本比用带WiFi的高端MCU要低。整个系统的架构可以这样理解STM32是大脑负责思考和决策传感器是眼睛和鼻子负责感知继电器和风机是手脚负责执行ESP8266是嘴巴负责把情况汇报出去OLED屏幕和蜂鸣器是表情负责现场表达。这个比喻虽然糙但能帮你快速建立整体认知。在方案选型上我做了几个关键决策这里展开说一下背后的逻辑。主控芯片选STM32F103C8T6。这颗芯片是Cortex-M3内核72MHz主频64KB Flash20KB RAM对于这个项目来说绰绰有余。它有3个USART一个接ESP8266一个接调试串口还有一个可以留给以后扩展。有2个I2C可以接OLED和温湿度传感器。有多个定时器可以用来做软件延时和PWM输出。最关键的是这颗芯片的生态太成熟了网上随便一搜就有大量的例程和踩坑记录遇到问题基本都能找到答案。温湿度传感器选DHT22AM2302。市面上常见的还有SHT30、SHT31、AHT10等。DHT22的精度是±0.5℃和±2%RH对于仓库环境监测来说够用了。它的优点是单总线协议、接线简单、价格便宜。缺点是响应速度慢两次读取之间至少要间隔2秒而且时序要求比较严格需要微秒级延时。如果你对精度要求更高可以换SHT30I2C接口精度±0.3℃和±2%RH读取速度也快很多但价格会贵一些。粉尘传感器选GP2Y1010AU0F。这是夏普的一款光学粉尘传感器输出模拟电压通过ADC采集。它的原理是红外LED发光粉尘颗粒反射光线到光电二极管上输出电压与粉尘浓度成正比。这个传感器能测PM2.5和PM10的混合浓度对于仓库环境来说足够。需要注意的是它需要脉冲驱动LED典型驱动周期是10ms其中LED点亮时间0.32ms要在点亮后0.28ms采样输出电压。这个时序如果用软件延时来做会占用CPU资源所以我用定时器中断来驱动。ESP8266选01S模块。这个模块体积小、价格低、AT指令成熟。虽然它只有2个GPIO可用但对于纯联网应用来说够了。我用的是安信可的AT固件版本是1.7.x支持MQTT指令。这里要提醒一句ESP8266的AT固件版本很多不同版本指令集有差异建议固定用一个版本不要随便刷。云平台选OneNet或者阿里云IoT。这两个平台我都用过OneNet的MQTT接入比较简单适合快速验证阿里云IoT功能更全但接入流程稍微复杂一些。这个项目里我用的是OneNet的多协议接入通过MQTT协议上传数据。ESP8266用AT指令连MQTT需要先连WiFi再连TCP再发MQTT连接报文流程比较长后面会详细讲。显示选0.96寸OLED。I2C接口128x64分辨率显示温湿度、粉尘浓度、设备状态足够了。相比LCD1602OLED不需要背光、对比度高、视角广而且I2C只需要两根线。执行机构选继电器模块。用两个继电器分别控制通风风机和除湿机。继电器选5V驱动的STM32的GPIO输出3.3V需要加三极管驱动或者用光耦隔离模块。我直接用了带光耦的继电器模块省事。整体设计思路就这些下面进入具体的细节解析。2. 核心细节解析与实操要点2.1 传感器采集的时序陷阱与解决方案DHT22的时序是这个项目里第一个坑。它的单总线协议是这样的主机拉低总线至少1ms作为起始信号然后释放总线DHT22响应后会拉低80us再拉高80us然后开始传输40位数据。每一位数据以50us低电平开始高电平持续时间决定是0还是1——26-28us表示070us表示1。问题在于STM32的HAL库延时函数HAL_Delay()是毫秒级的不够用。你需要微秒级延时。我试过用__NOP()循环来做但不同优化等级下循环次数不一样容易出问题。后来我改用定时器做微秒延时用TIM4预分频到1MHz也就是每计数一次1us。这样延时函数就准了。void delay_us(uint32_t us) { __HAL_TIM_SET_COUNTER(htim4, 0); while(__HAL_TIM_GET_COUNTER(htim4) us); }但这里还有个坑DHT22读取过程中不能被打断否则时序会乱。所以读之前要关中断读完再开。关中断的时间大概在5ms左右对于这个项目来说可以接受因为没有什么特别紧急的中断需要响应。另一个坑是DHT22的读取间隔。手册上写的是不小于2秒我实测下来如果间隔小于1.5秒读出来的数据会偶尔出错。所以我在代码里强制加了2秒的间隔用定时器来调度不依赖延时函数。GP2Y1010AU0F的时序也不简单。它需要你给LED驱动脚一个脉冲先拉低0.32ms点亮LED然后在0.28ms的时候采集模拟输出最后拉高0.32ms熄灭LED整个周期是10ms。这个时序如果用软件延时来做CPU基本被占满了。我的做法是用TIM3产生PWM频率100Hz占空比3.2%然后用这个PWM去驱动LED。同时在PWM的上升沿触发ADC采样用定时器触发ADC的方式让硬件自动完成采样CPU只需要在ADC中断里读数据就行。这里有个细节GP2Y1010AU0F的输出电压在无尘环境下大概是0.9V左右随着粉尘浓度升高电压会下降。所以计算浓度的时候要注意方向。我用的是这个公式粉尘浓度(ug/m3) (V0 - V) / 0.005其中V0是干净空气下的输出电压我实测大概是0.9V。但这个公式是经验公式不同批次的传感器会有差异建议用标准仪器校准一下。2.2 ESP8266的AT指令联网流程与避坑ESP8266的AT指令联网说起来简单做起来坑不少。整个流程是这样的发送AT确认模块响应发送ATCWMODE1设置为Station模式发送ATCWJAPSSID,password连接WiFi发送ATCIPMUX0设置为单连接模式发送ATCIPSTARTTCP,183.230.40.39,6002连接OneNet的MQTT服务器发送ATCIPSENDlength然后发送MQTT连接报文等待服务器返回CONNACK之后就是定期发送MQTT PUBLISH报文上传数据这里第一个坑是AT指令的响应处理。ESP8266返回的字符串里包含\r\n而且有时候会夹杂一些模块自己打印的调试信息。如果你用简单的字符串比较很容易误判。我的做法是写一个状态机逐字符接收遇到\r\n就认为一行结束然后判断这一行是否包含OK、ERROR、FAIL等关键字。第二个坑是超时处理。ESP8266连WiFi的时候如果密码错了它会一直重试不会返回FAIL。所以你必须自己加超时比如10秒没连上就重新配置。我见过有人在这里卡了一整天就是因为没加超时程序一直死在等待里。第三个坑是ATCIPSEND的长度计算。MQTT报文是二进制的里面可能有0x00如果你用strlen算长度遇到0x00就截断了。必须用实际的字节数。而且ATCIPSEND之后模块会返回然后你才能发数据。发完数据后模块会返回SEND OK。这个流程必须严格按顺序来。第四个坑是MQTT报文的构造。MQTT 3.1.1的CONNECT报文格式是固定的但里面的Client ID、Username、Password长度是可变的。你需要按照MQTT协议规范来拼报文。我建议直接找一个现成的MQTT报文构造函数不要自己从头写容易出错。OneNet的MQTT接入参数是服务器地址183.230.40.39端口6002Client ID用设备IDUsername用产品IDPassword用鉴权信息。这里给一个CONNECT报文的构造示例// MQTT CONNECT报文 uint8_t mqtt_connect[] { 0x10, 0x2A, // 固定头剩余长度42 0x00, 0x04, M, Q, T, T, // 协议名 0x04, // 协议级别 0x02, // 连接标志Clean Session 0x00, 0x3C, // 保持连接时间60秒 0x00, 0x0A, // Client ID长度10 // ... Client ID内容 // ... Username和Password };实际使用的时候Client ID、Username、Password的长度要根据你的实际值来调整剩余长度也要重新计算。2.3 自动控制逻辑的设计与阈值设定自动控制逻辑看起来简单就是超过阈值开风机、开除湿机但实际设计的时候要考虑几个问题。第一阈值怎么定对于电子制造仓库行业标准一般是温度18-28℃湿度40%-60%RH。但不同物料要求不一样锡膏一般要求湿度不超过60%MSD器件要求更严有的要求不超过50%。我建议把阈值做成可配置的存在STM32的Flash里通过串口或者按键可以修改。这样不用重新烧程序就能调整。第二回差怎么设如果阈值是60%湿度到了60.1%就开除湿机降到59.9%就关那除湿机会频繁启停既费电又伤设备。所以要设回差比如湿度超过60%开降到55%才关。这个回差一般设5%RH左右。温度的回差可以设2℃。第三延时怎么加传感器偶尔会有波动如果单次读数超阈值就动作可能会误触发。我的做法是连续3次读数都超阈值才动作每次间隔2秒。这样能过滤掉大部分干扰。第四优先级怎么排如果温度和湿度都超了先开哪个我的逻辑是除湿机优先因为除湿机工作时会发热可能会让温度进一步升高所以如果温度也超了在开除湿机的同时也要开通风。如果只是温度超了只开通风就行。第五手动模式怎么处理现场有时候需要手动控制比如维修的时候。所以要有手动/自动切换。我用一个按键来切换按下后进入手动模式再按一下切回自动。手动模式下另一个按键用来手动开关风机和除湿机。代码逻辑大概是这样if (auto_mode) { if (humidity hum_high_threshold) { hum_alarm_count; if (hum_alarm_count 3) { relay_dehumidifier ON; relay_fan ON; // 除湿时同时通风 } } else if (humidity hum_low_threshold) { hum_alarm_count 0; relay_dehumidifier OFF; if (temp temp_high_threshold) { relay_fan OFF; } } if (temperature temp_high_threshold) { temp_alarm_count; if (temp_alarm_count 3) { relay_fan ON; } } else if (temperature temp_low_threshold) { temp_alarm_count 0; if (humidity hum_high_threshold) { relay_fan OFF; } } }这里要注意除湿机和风机的关闭逻辑要互相考虑不能简单地把对方关掉。上面的代码里关除湿机的时候要检查温度是否还高关风机的时候要检查湿度是否还高。2.4 电源设计与抗干扰措施这个项目里电源设计是容易被忽视但非常关键的一环。系统里有STM323.3V、ESP82663.3V但峰值电流能到300mA、继电器5V、传感器5V、OLED3.3V。如果电源设计不好会出现ESP8266联网时复位、ADC采集值跳动、OLED花屏等问题。我的方案是输入用12V/2A的开关电源然后分三路。第一路用LM2596降到5V给继电器、传感器、ESP8266供电。第二路用AMS1117-3.3降到3.3V给STM32和OLED供电。第三路也是5V但单独给ESP8266中间加一个1000uF的电解电容和0.1uF的陶瓷电容用来吸收ESP8266联网时的电流尖峰。这里有个细节ESP8266的峰值电流很大如果和STM32共用一路3.3V联网的时候可能会把STM32的电压拉低导致复位。所以一定要分开供电或者在ESP8266的电源脚旁边加一个大电容。抗干扰方面ADC采集粉尘传感器的时候读数会有跳动。我在软件里加了滑动平均滤波每次采集10个值去掉最大和最小剩下的取平均。这样读数就稳多了。另外继电器的线圈在断电时会产生反向电动势可能干扰MCU。我在继电器线圈两端加了续流二极管并且在继电器和MCU之间用了光耦隔离。3. 实操过程与核心环节实现3.1 硬件搭建与接线先列一下完整的物料清单物料型号数量备注主控板STM32F103C8T6最小系统板1核心板WiFi模块ESP8266-01S1需配3.3V供电温湿度传感器DHT221单总线粉尘传感器GP2Y1010AU0F1模拟输出显示屏0.96寸OLED1I2C接口继电器模块5V光耦隔离2控制风机和除湿机蜂鸣器有源蜂鸣器1报警按键轻触按键3设置/手动/复位电源12V/2A开关电源1总输入降压模块LM2596112V转5V降压模块AMS1117-3.315V转3.3V接线方面STM32的PA0接DHT22的数据脚PA1接粉尘传感器的模拟输出PA2和PA3做I2C接OLEDPA9和PA10做串口1接ESP8266PA11和PA12接继电器PA13接蜂鸣器PB0、PB1、PB2接按键。这里要注意ESP8266的供电是3.3V但它的TX和RX是3.3V电平可以直接接STM32的串口。不过ESP8266的RX对电压比较敏感如果STM32的TX输出3.3V一般没问题。但如果你用的是5V的STM32板子就要加电平转换。DHT22的数据脚需要接一个4.7K到10K的上拉电阻到3.3V。我用的4.7K实测稳定。粉尘传感器的LED驱动脚接STM32的PA8用定时器PWM驱动。模拟输出接PA1用ADC1的通道1采集。继电器模块的输入接STM32的GPIO输出接风机和除湿机的电源线。注意继电器的触点容量要够风机和除湿机的启动电流可能比较大建议选10A以上的继电器。3.2 STM32工程搭建与关键代码我用的是Keil MDK 5配合STM32CubeMX生成初始化代码。这里说一下CubeMX的配置要点。时钟配置外部晶振8MHzPLL倍频到72MHz。APB1分频到36MHzAPB2分频到72MHz。串口配置USART1波特率1152008位数据1位停止无校验。开启接收中断和空闲中断。空闲中断用来判断一帧数据接收完成。定时器配置TIM4用于微秒延时预分频72-1计数周期65535。TIM3用于粉尘传感器LED驱动PWM模式频率100Hz占空比3.2%。TIM2用于系统滴答1ms中断。ADC配置ADC1通道1连续转换模式由TIM3的TRGO触发。DMA传输缓冲区大小10。I2C配置I2C1标准模式100kHz用于OLED。GPIO配置继电器输出推挽按键输入上拉蜂鸣器输出推挽。生成代码后需要自己添加的部分主要是DHT22驱动、OLED驱动、ESP8266驱动、MQTT报文构造、控制逻辑。DHT22的驱动代码大概是这样#define DHT22_PIN GPIO_PIN_0 #define DHT22_PORT GPIOA void DHT22_Start(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin DHT22_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DHT22_PORT, GPIO_InitStruct); HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_RESET); delay_us(1200); HAL_GPIO_WritePin(DHT22_PORT, DHT22_PIN, GPIO_PIN_SET); delay_us(30); GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(DHT22_PORT, GPIO_InitStruct); } uint8_t DHT22_ReadByte(void) { uint8_t byte 0; for (int i 0; i 8; i) { while (!HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN)); // 等待50us低电平结束 delay_us(40); byte 1; if (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN)) { byte | 1; } while (HAL_GPIO_ReadPin(DHT22_PORT, DHT22_PIN)); // 等待高电平结束 } return byte; }读取的时候要关中断读完再开。读出来的40位数据是8位湿度整数、8位湿度小数、8位温度整数、8位温度小数、8位校验和。校验和等于前四个字节相加的低8位。ESP8266的驱动我用的是状态机方式不阻塞主循环。定义一个结构体typedef struct { uint8_t rx_buffer[256]; uint16_t rx_index; uint8_t rx_complete; uint8_t state; uint32_t timeout; } ESP8266_HandleTypeDef;串口空闲中断里把接收到的数据存入rx_buffer置位rx_complete。主循环里检查rx_complete然后根据state做相应的处理。MQTT报文构造我写了一个函数uint16_t MQTT_BuildConnect(uint8_t *buffer, const char *client_id, const char *username, const char *password) { uint16_t index 0; uint16_t remaining_length 10 strlen(client_id) 2 strlen(username) 2 strlen(password); buffer[index] 0x10; // 剩余长度编码这里简化处理假设小于128 buffer[index] remaining_length; // 协议名 buffer[index] 0x00; buffer[index] 0x04; buffer[index] M; buffer[index] Q; buffer[index] T; buffer[index] T; // 协议级别 buffer[index] 0x04; // 连接标志 buffer[index] 0xC2; // Clean Session Username Password // 保持连接时间 buffer[index] 0x00; buffer[index] 0x3C; // Client ID buffer[index] 0x00; buffer[index] strlen(client_id); memcpy(buffer[index], client_id, strlen(client_id)); index strlen(client_id); // Username buffer[index] 0x00; buffer[index] strlen(username); memcpy(buffer[index], username, strlen(username)); index strlen(username); // Password buffer[index] 0x00; buffer[index] strlen(password); memcpy(buffer[index], password, strlen(password)); index strlen(password); return index; }上传数据的PUBLISH报文也类似需要构造主题名和负载。OneNet的MQTT上传主题一般是$dp负载是JSON格式。3.3 云平台配置与数据上传OneNet的配置流程是这样的注册账号创建产品选择MQTT协议然后添加设备。设备创建后会得到设备ID、产品ID和鉴权信息。这三个值就是MQTT连接时的Client ID、Username和Password。数据上传的格式OneNet支持JSON。我用的格式是{ temperature: 25.6, humidity: 55.2, dust: 35 }上传的主题是$dpQoS用0。ESP8266发送的时候先发ATCIPSENDlength等模块返回然后把MQTT PUBLISH报文发过去。这里有个细节OneNet的MQTT服务器对报文长度有限制单次上传不要超过1KB。我们的数据很小没问题。数据上传的频率我设的是每30秒一次。太频繁了费流量太慢了实时性不好。30秒对于仓库环境监测来说足够了。3.4 本地显示与报警实现OLED显示我用的是u8g2库这个库支持很多种OLED移植也方便。显示内容分四行第一行温度第二行湿度第三行粉尘浓度第四行设备状态。u8g2_ClearBuffer(u8g2); u8g2_SetFont(u8g2, u8g2_font_6x10_tf); u8g2_DrawStr(u8g2, 0, 12, Temp:); u8g2_DrawStr(u8g2, 40, 12, temp_str); u8g2_DrawStr(u8g2, 0, 26, Humi:); u8g2_DrawStr(u8g2, 40, 26, humi_str); u8g2_DrawStr(u8g2, 0, 40, Dust:); u8g2_DrawStr(u8g2, 40, 40, dust_str); u8g2_DrawStr(u8g2, 0, 54, Fan:); u8g2_DrawStr(u8g2, 40, 54, fan_state ? ON : OFF); u8g2_SendBuffer(u8g2);报警逻辑当温度、湿度或粉尘任一超过阈值时蜂鸣器以1Hz的频率鸣叫同时OLED上对应的数值闪烁显示。如果超过阈值持续5分钟没有恢复就认为是大问题蜂鸣器长鸣。按键功能三个按键分别是设置键、加键、减键。设置键用来进入设置模式加键和减键用来调整阈值。设置模式下OLED显示当前阈值按设置键切换要调整的参数。设置完成后长按设置键保存到Flash。4. 常见问题与排查技巧实录4.1 调试过程中遇到的典型问题问题一DHT22读出来全是0或者全是1。这个问题的原因通常是时序不对。我排查的时候用示波器看了波形发现起始信号的低电平时间不够。手册上要求至少1ms我一开始用了800us就不行。改成1200us后正常了。另外上拉电阻也很关键我试过10K的波形上升沿太慢读出来偶尔出错。换成4.7K后稳定了。问题二ESP8266连不上WiFi。这个问题的排查步骤是这样的先用串口助手手动发AT指令确认模块能正常响应。如果手动都连不上那就是模块或者WiFi的问题。如果手动能连上但程序里连不上那就是程序的问题。我遇到过一次是因为程序里发AT指令后等待时间太短模块还没响应就发下一条了。后来把等待时间从1秒改成3秒就好了。问题三MQTT连接被服务器拒绝。OneNet的MQTT连接被拒绝最常见的原因是Client ID、Username、Password填错了。注意OneNet的Username是产品ID不是产品名称。Password是鉴权信息不是设备名称。这三个值一定要从OneNet的控制台里复制不要手打。问题四ADC采集的粉尘值跳动很大。这个问题的原因可能是电源纹波或者传感器本身噪声。我在电源脚加了100uF和0.1uF的电容软件里加了滑动平均滤波跳动从±20降到了±5以内。另外GP2Y1010AU0F的输出阻抗比较高STM32的ADC输入阻抗有限建议加一个电压跟随器。我偷懒没加但通过延长采样时间解决了。问题五继电器动作时STM32复位。这是典型的电源干扰问题。继电器线圈断电时会产生反向电动势通过电源线传导到MCU。我在继电器线圈两端加了续流二极管并且在继电器和MCU之间用了光耦隔离问题就解决了。另外继电器的电源和MCU的电源要分开走线不要共用一根线。问题六OLED显示花屏。I2C的时序问题。STM32的硬件I2C有时候会卡死我后来改用软件模拟I2C就稳定了。软件I2C的延时用delay_us(2)速度虽然慢一点但可靠性高很多。4.2 常见问题速查表现象可能原因排查方法解决方案DHT22读数全0时序不对示波器看波形调整延时换4.7K上拉ESP8266连不上WiFi等待时间不够手动发AT测试增加等待时间到3秒MQTT连接被拒参数填错核对OneNet控制台复制粘贴不要手打粉尘值跳动大电源噪声示波器看电源纹波加滤波电容软件滤波继电器动作复位电源干扰分开供电加续流二极管光耦隔离OLED花屏I2C时序换软件I2C软件模拟I2C程序跑飞看门狗未开检查看门狗配置开启独立看门狗数据上传失败报文格式错串口打印报文核对MQTT协议格式4.3 实操心得与避坑建议第一条心得先分模块调试再联调。我一开始想一口气把整个系统写完再调试结果出了问题不知道是哪里的。后来改成先调DHT22再调OLED再调ESP8266最后联调效率高很多。每个模块单独调通后联调的时候问题就少很多。第二条心得串口打印是最好的调试工具。在关键位置加串口打印把传感器的值、ESP8266的响应、MQTT的报文都打印出来一眼就能看出问题在哪。我习惯用printf重定向到串口方便得很。第三条心得电源一定要留余量。我一开始用的是一个1A的电源结果ESP8266联网的时候电流不够模块反复复位。换成2A的电源后就好了。电源的余量至少要是实际电流的1.5倍。第四条心得AT指令的响应要逐字符解析。不要用strstr去匹配因为ESP8266返回的数据里可能包含OK这样的字符串但不是你想要的那个。我写了一个逐行解析的函数遇到\r\n就认为一行结束然后判断这一行的内容。第五条心得MQTT的Keep Alive要设合理。我一开始设的60秒但OneNet的服务器有时候会主动断开。后来改成120秒就稳定了。Keep Alive的意思是如果在这个时间内没有收到任何报文客户端就要发一个PINGREQ。如果服务器在这个时间的1.5倍内没收到任何报文就会断开连接。第六条心得Flash存储要加磨损均衡。如果频繁写Flash存阈值Flash会坏。我的做法是只在设置模式下才写Flash而且写之前先读出来比较如果值没变就不写。另外STM32F103的Flash擦写次数大概是1万次正常使用几年没问题。第七条心得看门狗一定要开。工业现场电磁干扰大程序可能会跑飞。开启独立看门狗超时时间设2秒在主循环里喂狗。这样即使程序跑飞也能自动复位。第八条心得外壳和接线要规范。我见过有人把板子直接放在铁皮柜里结果短路烧了。建议用塑料外壳接线用端子不要直接焊。传感器和继电器的线要分开走避免干扰。这个项目从开始到稳定运行大概花了三周时间。其中调试ESP8266和MQTT花的时间最多大概占了一半。硬件搭建和STM32代码其实很快两天就搞定了。如果你也要做类似的项目我的建议是先把ESP8266的AT指令和MQTT报文调通这部分是最容易卡住的。另外OneNet的文档虽然全但有些细节写得不清楚遇到问题多搜搜社区基本都能找到答案。最后再分享一个小技巧如果你觉得OneNet的MQTT接入太麻烦可以先用HTTP协议上传数据ESP8266发HTTP POST请求比MQTT简单很多。等HTTP调通了再换成MQTT。这样能快速看到数据上传的效果增加信心。
返回列表