很多玩Arduino ESP8266做项目的朋友,肯定都碰到过这种情况:辛辛苦苦写好的联网代码,设备一放到现场,没多久就断了WiFi,要么半天连不上,要么连是连上了但不发数据,跟个“哑巴”似的。尤其是做温湿度监测、智能插座这种需要一直在线的项目,断连就等于废了一半功能。今天就给大家讲一套我自己用了好几个项目的稳定方案——把心跳包和自动复位电路结合,解决ESP8266的WiFi断线重连问题。
一、普通的WiFi重连为啥不好用?
很多新手一开始会直接写:WiFi断了就再连,连不上再重试。这种方法其实坑很多:比如刚断就连,路由器可能还在释放之前的连接,重试也白搭;或者ESP8266假死,WiFi显示连上了但数据传不出去,程序还在傻等,根本不知道自己已经断了。还有的只靠检测WiFi的信号强度判断,信号满格也可能断连,这种误判太常见了。所以我们需要的是“能真正确认设备还和服务器通着”的方法,再加最后兜底的硬件保障。
二、心跳包:给WiFi装个“健康监测器”
心跳包是什么?说白了就是让ESP8266定时给服务器发一个特别小的数据包,比如只有几字节的“我还活着”。服务器那边只要连续几次没收到这个包,就说明ESP和服务器的连接出问题了,这时候ESP自己就知道要重连了。这种方法比单纯测WiFi信号准多了——哪怕WiFi信号满格,只要心跳收不到,就是真的断连了。
2.1 心跳包的写法(基础示例)
这里我们用最常用的TCP连接举例子,技术栈是Arduino ESP8266,用WiFiClient来和服务器通信,用millis()函数(不是delay()!delay会卡程序,后面会说为啥)来定时发心跳。
#include <ESP8266WiFi.h>
// WiFi配置
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
// 服务器地址和端口(比如自己搭的简单服务器,或者用第三方平台)
const char* serverHost = "192.168.1.100";
const uint16_t serverPort = 8080;
WiFiClient client;
unsigned long lastHeartbeat = 0; // 上一次发心跳的时间
const long heartbeatInterval = 3000; // 心跳间隔,3秒发一次
void setup() {
Serial.begin(115200);
// 先连WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi连接成功!");
}
void loop() {
// 先判断WiFi有没有连,或者客户端有没有通
if (!client.connected()) {
// 重连服务器
if (client.connect(serverHost, serverPort)) {
Serial.println("服务器连接成功");
} else {
Serial.println("服务器连接失败,1秒后重试");
delay(1000);
return;
}
}
// 定时发心跳,用millis不卡程序
if (millis() - lastHeartbeat > heartbeatInterval) {
lastHeartbeat = millis();
// 发心跳包,就发个简单的字符就行,比如"ping"
client.println("ping");
Serial.println("发了心跳包");
}
}
这里要注意:为什么不用delay?因为如果用delay(3000),在延迟的3秒里,程序啥都干不了,比如如果中途WiFi断了,程序要等3秒才会检测到,反应太慢。而用millis(),不管程序在干嘛,时间都在走,到点就触发心跳,反应快。
三、自动复位电路:硬件级的终极兜底
就算心跳包检测到断连,ESP软件重连也可能失败——比如路由器抽风,或者ESP本身的软件死锁,这时候再想连都白搭。这时候就需要硬件来救场:给ESP的复位引脚(RST)一个短脉冲,让ESP重启,相当于给电脑按重启键,不管软件啥状态,重启就好。
3.1 复位电路的简单实现
不用搞复杂的电路,只需要一个NPN三极管、一个1K电阻、一个10K电阻,还有一根线接到ESP8266的GPIO引脚(比如D1引脚)。当程序判断到断连次数超过阈值,就给D1引脚一个高电平,通过三极管拉低RST引脚,产生一个复位脉冲,几毫秒后松开,ESP就自动重启了。 我自己用的电路特别简单,焊在面包板上都能用,新手也不用怕焊坏。代码里只要控制这个GPIO引脚就行,不用焊太复杂的东西,只要知道这个电路是“软件搞不定就重启硬件”就行。
四、完整的稳定方案代码(带心跳+复位)
把心跳和复位结合起来,再加上断连次数的判断,这样就不会随便重启,只有真的连不上的时候才复位。技术栈还是Arduino ESP8266,代码里加了断连计数和复位控制,非常适合直接用。
#include <ESP8266WiFi.h>
// 配置部分,直接改这里就行
const char* ssid = "你的WiFi名称";
const char* password = "你的WiFi密码";
const char* serverHost = "192.168.1.100";
const uint16_t serverPort = 8080;
const int resetPin = D1; // 接复位电路的GPIO引脚
const long heartbeatInterval = 3000; // 心跳间隔3秒
const int maxMissedHeartbeats = 5; // 最多丢5次心跳就复位
WiFiClient client;
unsigned long lastHeartbeat = 0;
int missedHeartbeatCount = 0;
void setup() {
Serial.begin(115200);
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH); // 初始状态是高,不会复位
// 连WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("WiFi连好了!");
}
void loop() {
// 1. 处理WiFi连接
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi断了,准备重连");
WiFi.disconnect();
delay(1000);
WiFi.begin(ssid, password);
return;
}
// 2. 处理服务器连接
if (!client.connected()) {
Serial.println("服务器断了,重连中");
if (client.connect(serverHost, serverPort)) {
Serial.println("服务器连好了");
missedHeartbeatCount = 0; // 连上了就重置丢包计数
} else {
Serial.println("服务器连不上");
missedHeartbeatCount++;
// 如果丢包超过次数,触发复位
if (missedHeartbeatCount >= maxMissedHeartbeats) {
Serial.println("丢包太多,准备复位");
digitalWrite(resetPin, LOW);
delay(100); // 复位脉冲100毫秒,够触发重启
digitalWrite(resetPin, HIGH);
delay(2000); // 等重启完再继续
}
return;
}
}
// 3. 定时发心跳
if (millis() - lastHeartbeat > heartbeatInterval) {
lastHeartbeat = millis();
if (client.println("ping")) { // 发心跳成功
missedHeartbeatCount = 0; // 成功发了就重置计数
Serial.println("心跳发了,正常");
} else { // 发失败,丢包+1
missedHeartbeatCount++;
Serial.println("心跳发失败,丢包计数:" + String(missedHeartbeatCount));
if (missedHeartbeatCount >= maxMissedHeartbeats) {
// 触发复位
digitalWrite(resetPin, LOW);
delay(100);
digitalWrite(resetPin, HIGH);
delay(2000);
}
}
}
}
这个代码可以直接改配置就能用,新手只要把WiFi名称、密码、服务器地址改成自己的就行,复位电路接好D1就ok。
五、这个方案适合哪些场景?
比如你做的室内温湿度采集,要每天24小时发数据到手机;或者户外的太阳能监测设备,装在树上不容易碰,断连了要自己修;还有智能门锁的联网模块,不能连个WiFi就断了;甚至是鱼缸水质监测,断连了不知道水坏了,那可是大问题。这些场景都需要稳定联网,这个方案都能搞定。
六、这个方案的优缺点
优点:一是稳,软件心跳能真正确认连接状态,硬件复位兜底,几乎不会出现一直断连的情况;二是简单,代码不用写太复杂,电路焊几个元件就行;三是开源,不用花任何钱,都是ESP8266通用的东西。 缺点:多了个小电路,虽然很简单但要多焊一步;还有心跳间隔要选对,选太短会多消耗点流量(不过ESP8266用的都是小流量的项目,比如每次发几个字节,3秒一次,一天才几百K,根本不费流量);另外复位脉冲的时间要调好,太短触发不了复位,太长可能会有问题,100毫秒左右就刚好。
七、要注意的几个坑
第一个坑:一定要用millis()代替delay(),不然程序卡的时候心跳不准,或者连WiFi的时候根本不反应,很多新手踩这个坑。第二个坑:复位引脚的初始状态,一定要是高电平,不然ESP一开机就复位,永远连不上。第三个坑:心跳包不要发太大,比如别发个几K的数据,占带宽还容易丢,就发个几字节的小字符串就行。第四个坑:maxMissedHeartbeats别设太小,比如设成1的话刚断连就复位,太频繁,设成5左右刚好,给路由器一点恢复的时间。
八、总结
这套把心跳包和自动复位结合的方案,是我做ESP8266项目用的最多的,从之前做的智能温湿度计到现在的户外太阳能监测,从来没出现过一直断连的情况。不管是新手还是有经验的开发者,只要会一点点Arduino的基础,就能很快搭起来,不用搞复杂的物联网平台,改改配置就能用。如果你也碰到ESP8266联网不稳定的问题,试试这套方法,肯定能解决大部分问题。
评论
围绕“Arduino ESP8266 WiFi断线重连策略的设计:心跳包发送与自动复位电路结合的稳定方案”参与讨论