文章目录
- 问题一
- 现象描述
- 原因分析
- 解决方法
- 问题二
- 现象描述
- 原因分析
- 解决方法
- 问题三
- 现象描述
- 原因分析
- 解决方法
- 实例应用
问题一
现象描述
- 使用
WiFi.softAP
方法建立网络,有时候很难连接上; - 改用
WiFi.begin
切换为STA模式后用其他设备扫描网络发现竟然前次设置的AP模式网络还在;
原因分析
阅读Arduino for esp8266库文档可以知道用该方式来开发除了我们写的代码外还有很多功能在运作,比如使用 WiFi.begin
连接过的网络默认情况下会被存储,并在下次上电时自动连接。
是不是在使用 WiFi.softAP
模式的时候我前次实验用过的 WiFi.begin
功能的网络还存在,并且上电就去尝试连接了?而在使用 WiFi.begin
模式下存在之前的AP模式网络是不是也因为这个原因?是不是因为这些原因导致了上面的问题?
解决方法
虽然没在库中找到完整的相关描述,但是解决方法倒是有(实测可行),在开启STA或AP功能前强制设定工作模式,使用下面方法:
WiFi.mode(m)
:set mode toWIFI_AP
,WIFI_STA
,WIFI_AP_STA
orWIFI_OFF
.
从上面方法的参数中也可以知道ESP8266其实是可能会同时工作在AP和STA模式下的,要是该模式不是你想要的,最好强制设置下。
问题二
现象描述
网络运行不稳定,有时候会断开或失去连接,特别是在工作较频繁时该现象更严重。
原因分析
阅读Arduino for esp8266库文档可以看到下面描述:
Remember that there is a lot of code that needs to run on the chip besides the sketch when WiFi is connected. WiFi and TCP/IP libraries get a chance to handle any pending events each time the
loop()
function completes, OR whendelay
is called. If you have a loop somewhere in your sketch that takes a lot of time (>50ms) without callingdelay
, you might consider adding a call todelay
function to keep the WiFi stack running smoothly.
There is also ayield()
function which is equivalent todelay(0)
. ThedelayMicroseconds
function, on the other hand, does not yield to other tasks, so using it for delays more than 20 milliseconds is not recommended.
上文的意思就是说使用Arduino for esp8266来开发时除了你自己的代码外还有很多TCP/IP的工作需要运行,这些工作在 loop()
或是 delay
亦或是 yield()
过程中执行。如果你的程序耗时(>50ms),请调用一下 delay
函数 或是 yield()
(等价于 delay(0)
)。
解决方法
解决方法就按上文所述。
问题三
现象描述
使用Web Server功能时,在客户端连接后长时间无响应。
原因分析
分析程序可看到 while (client.connected()){……}
这里用了 while
但是可能因为某些原因在这内部并没有执行到跳出的动作,导致一直在此处循环。
解决方法
while
里面加入超时处理。
实例应用
针对上述的几个问题这里用前一篇文章中的代码进行修改作为示范:
#include <ESP8266WiFi.h>
/*** 该工程可以在2.4.0版本esp8266库中运行,没在更高版本库中进行测试 ***/
const char *ssid = "********";
const char *password = "********";
WiFiServer server(80);
String readString = ""; //建立一个字符串对象用来接收存放来自客户的数据
//响应头
String responseHeaders =
String("") +
"HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html\r\n" +
"Connection: close\r\n" +
"\r\n";
//网页
String myhtmlPage =
String("") +
"<html>" +
"<head>" +
" <title>ESP8266 Web Server Test</title>" +
" <script defer=\"defer\">" +
" function ledSwitch() {" +
" var xmlhttp;" +
" if (window.XMLHttpRequest) {" +
" xmlhttp = new XMLHttpRequest();" +
" } else {" +
" xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");" +
" }" +
" xmlhttp.onreadystatechange = function () {" +
" if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {" +
" document.getElementById(\"txtState\").innerHTML = xmlhttp.responseText;" +
" }" +
" }," +
" xmlhttp.open(\"GET\", \"Switch\", true);" +
" xmlhttp.send(); " +
" }" +
" </script>" +
"</head>" +
"<body>" +
" <div id=\"txtState\">Unkwon</div>" +
" <input type=\"button\" value=\"Switch\" onclick=\"ledSwitch()\">" +
"</body>" +
"</html>";
bool isLedTurnOn = false; // 记录LED状态
void setup()
{
pinMode(2, OUTPUT);
digitalWrite(2, HIGH); // 熄灭LED
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.mode(WIFI_STA); //******设置为STA模式******
WiFi.setAutoConnect(false); //关闭上电时自动连接到已保存网络
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
server.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}
void loop()
{
WiFiClient client = server.available(); //尝试建立客户对象
if (client) //如果当前有客户可用
{
boolean currentLineIsBlank = true;
Serial.println("[Client connected]");
unsigned long previousMillis = millis(); //******获取当前时间******
while (client.connected()) //如果客户端建立连接
{
if(millis() - previousMillis >= 50)yield(); //******如果50ms未处理完则调用延时处理网络事务******
if(millis() - previousMillis >= 5000)break; //******如果5000ms则认定超时,立即跳出******
if (client.available()) //等待有可读数据
{
char c = client.read(); //读取一字节数据
readString += c; //拼接数据
/************************************************/
if (c == '\n' && currentLineIsBlank) //等待请求头接收完成(接收到空行)
{
//比较接收到的请求数据
if (readString.startsWith("GET / HTTP/1.1")) //如果是网页请求
{
client.print(responseHeaders); //向客户端输出网页响应
client.print(myhtmlPage); //向客户端输出网页内容
client.print("\r\n");
}
else if (readString.startsWith("GET /Switch")) //如果是改变LED状态请求
{
if (isLedTurnOn == false)
{
digitalWrite(2, LOW); // 点亮LED
client.print("LED has been turn on");
isLedTurnOn = true;
}
else
{
digitalWrite(2, HIGH); // 熄灭LED
client.print("LED has been turn off");
isLedTurnOn = false;
}
}
else
{
client.print("\r\n");
}
break;
}
if (c == '\n')
{
currentLineIsBlank = true; //开始新行
}
else if (c != '\r')
{
currentLineIsBlank = false; //正在接收某行中
}
/************************************************/
}
}
delay(1); //等待客户完成接收
client.stop(); //结束当前连接:
Serial.println("[Client disconnected]");
Serial.println(readString); //打印输出来自客户的数据
readString = "";
}
}
上文中带 //******XXXXXX******
注释的那几行就是针对上述几个问题所添加的。