ESP8266 UDP parsePacket 在做其他事情时不起作用
ESP8266 UDP parsePacket does not work when doing other stuff
这几天考验我心情的问题是,虽然我的ESP8266芯片完全可以在while循环中用parsePacket抓包,但是当我想让BOTH都听传入的数据包时,它完全错过了这些,而且允许我的 ESP8266 读取传感器并通过 wifi 发送这些。
所以我删除了与传感器有关的所有内容并粘贴了下面的代码,但这是正在发生的事情。
- 在Setup()中,ESP设置wifi、SoftAP节点、UDP并进行配置。
- 然后它会进入一个 while 循环,在其中侦听通过 wifi 传入的包;这告诉 ESP 开始吐出数据。
- 当 ESP 收到一个数据包时(这是我代码中的 "A. <<<" 注释并且工作正常),代码移动到 Loop() 部分并且传感器开始吐出通过 wifi 发送的数据
我的问题是这一步:
- 在读取传感器和通过 wifi 发送数据期间,我希望 ESP8266 也能够通过 wifi 接收传入的数据包(这是我代码中的 "B. <<<" 注释并且不起作用),ESP不断通过 wifi 发送传感器数据,但它没有收到任何数据包
我的猜测是 A. 工作正常,因为 'while' 条件将允许 parsePacket 始终捕获传入数据包。因为 B. 在 void 循环内,我不能使用 'while' 条件,而是使用 'if' 语句,parsePacket 命令没有在正确的时刻请求传入的包。我无法实施解决此问题的方法。相当多的搜索并没有真正的帮助,我无法想象只有我一个人遇到这个问题。
我发现的一些相关内容:
- 不幸的是,WifiEventHandler 没有列出与接收数据包相关的事件:https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/generic-class.html
- 我也找到了这个主题,但我无法让它工作,而且这个问题的答案似乎不完整:Making a UDP class which doesn't block an ESP8266 / Arduino
非常感谢您的帮助和反馈!
这是我的代码:
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
String SendString;
String SendBuffer = "STR ";
boolean SendSuccessful;
char SendChar[32];
// wifi connection variables
const char* password = #########;
boolean wifiConnected = false;
String ssid_string;
char ssid[10];
// UDP variables
unsigned int localPort = 8888;
WiFiUDP UDP;
boolean udpConnected = false;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
char ReplyBuffer[500] = "acknowledged"; // a string to send back
void setup(void) {
Serial.begin(115200);
//Setup all my sensors, code not relevant
//Connect Wifi
ssid_string = "DRILL_" + String(chip_id);
ssid_string.toCharArray(ssid, 500);
SetupWifi(ssid);
}
void loop(void) {
//B. <<<< SO THIS IS THE PART IN THE LOOP THAT IS NOT WORKING
int packetSize = UDP.parsePacket();
packetSize = UDP.parsePacket();
if (packetSize) {
Serial.println("");
Serial.print("Received packet");
// read the packet into packetBufffer
UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
int value = packetBuffer[0] * 256 + packetBuffer[1];
Serial.println(value);
}
//Read out all my sensors, code not relevant, paste all sensor data in one string
//SendString over serial
Serial.print(SendString);
SendIntervalUDP(1); // Send SendString over UDP every x measurements (see function below)
//Listen to serial
if (Serial.available() > 0) {
String Received = Serial.readString();
Serial.println("ESP received: " + Received);
}
}
下面是设置wifi和通过wifi发送数据的一些支持功能
unsigned long previousWifiStatMillis;
//Connect wifi during setup
void SetupWifi(char my_ssid[]) {
// WiFi init
wifiConnected = createAP(my_ssid);
udpConnected = connectUDP();
// Wait for first packet
Serial.println("Waiting for start");
//A. <<<< SO THIS IS THE PART IN THE CODE THAT IS ACTUALLY WORKING
int packetSize = UDP.parsePacket();
while (packetSize < 1) {
packetSize = UDP.parsePacket();
yield(); // Allow the background functions to work
//Listen to serial
if (Serial.available() > 0) {
String Received = Serial.readString();
Serial.println("I received: " + Received);
if (Received.substring(0) == "S") {
Serial.println("Starting..");
break;
}
}
if (packetSize)
{
Serial.println("");
Serial.print("Received packet");
// read the packet into packetBufffer
UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
int value = packetBuffer[0] * 256 + packetBuffer[1];
Serial.println(value);
}
}
}
// connect to UDP – returns true if successful or false if not
boolean connectUDP() {
boolean state = false;
Serial.println("");
Serial.println("Connecting to UDP");
if (UDP.begin(localPort) == 1) {
Serial.println("Connection successful");
state = true;
}
else {
Serial.println("Connection failed");
}
return state;
}
// connect to wifi – returns true if successful or false if not
boolean createAP(char my_ssid[]) {
boolean state = true;
int i = 0;
WiFi.softAP(my_ssid, password); // Start the access point
WiFi.mode(WIFI_AP);
Serial.print("Access Point \"");
Serial.print(my_ssid);
Serial.println("\" started");
Serial.print("IP address:\t");
Serial.println(WiFi.softAPIP()); // Send the IP address of the ESP8266 to the computer
state = true;
return state;
}
// connect to wifi – returns true if successful or false if not
boolean connectWifi(char my_ssid[]) {
boolean state = true;
int i = 0;
WiFi.begin(my_ssid, password);
Serial.println("");
Serial.println("Connecting to WiFi");
// Wait for connection
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (i > 20) {
state = false;
break;
}
i++;
}
if (state) {
Serial.println("");
Serial.print("Connected to ");
Serial.println(my_ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
else {
Serial.println("");
Serial.println("Connection failed.");
}
return state;
}
void SendIntervalUDP(int interval) {
//Send an udp packet every x packets with x the interval
j++;
if (j > (interval-1) ) {
j = 0;
//SendString over wifi
if (wifiConnected) {
if (udpConnected) {
// send a reply, to predetermined hotspot
UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
SendBuffer.toCharArray(ReplyBuffer, 500);
UDP.write(ReplyBuffer);
UDP.endPacket();
}
}
SendBuffer = "";
}
}
"Generic Class" 中的 WiFi 事件适用于传输层以下的 OSI 级别。 TCP 和 UDP 是传输层。
要接收 UDP 数据包,您必须在 loop()
中调用 UDP.parsePacket();
(或在从 loop()
调用的函数中),就像所有其他实现 Arduino [=13= 的 Arduino 网络库一样]基地class.
如果数据包可用,调用 parsePacket
将数据包读入内部缓冲区并 returns 数据包的大小。下一次调用 parsePacket
会清除缓冲区并在可用时用新数据包填充它。您调用 parsePacket
两次,第二次总是 returns 什么都没有。
这几天考验我心情的问题是,虽然我的ESP8266芯片完全可以在while循环中用parsePacket抓包,但是当我想让BOTH都听传入的数据包时,它完全错过了这些,而且允许我的 ESP8266 读取传感器并通过 wifi 发送这些。
所以我删除了与传感器有关的所有内容并粘贴了下面的代码,但这是正在发生的事情。
- 在Setup()中,ESP设置wifi、SoftAP节点、UDP并进行配置。
- 然后它会进入一个 while 循环,在其中侦听通过 wifi 传入的包;这告诉 ESP 开始吐出数据。
- 当 ESP 收到一个数据包时(这是我代码中的 "A. <<<" 注释并且工作正常),代码移动到 Loop() 部分并且传感器开始吐出通过 wifi 发送的数据
我的问题是这一步:
- 在读取传感器和通过 wifi 发送数据期间,我希望 ESP8266 也能够通过 wifi 接收传入的数据包(这是我代码中的 "B. <<<" 注释并且不起作用),ESP不断通过 wifi 发送传感器数据,但它没有收到任何数据包
我的猜测是 A. 工作正常,因为 'while' 条件将允许 parsePacket 始终捕获传入数据包。因为 B. 在 void 循环内,我不能使用 'while' 条件,而是使用 'if' 语句,parsePacket 命令没有在正确的时刻请求传入的包。我无法实施解决此问题的方法。相当多的搜索并没有真正的帮助,我无法想象只有我一个人遇到这个问题。
我发现的一些相关内容:
- 不幸的是,WifiEventHandler 没有列出与接收数据包相关的事件:https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/generic-class.html
- 我也找到了这个主题,但我无法让它工作,而且这个问题的答案似乎不完整:Making a UDP class which doesn't block an ESP8266 / Arduino
非常感谢您的帮助和反馈!
这是我的代码:
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
String SendString;
String SendBuffer = "STR ";
boolean SendSuccessful;
char SendChar[32];
// wifi connection variables
const char* password = #########;
boolean wifiConnected = false;
String ssid_string;
char ssid[10];
// UDP variables
unsigned int localPort = 8888;
WiFiUDP UDP;
boolean udpConnected = false;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
char ReplyBuffer[500] = "acknowledged"; // a string to send back
void setup(void) {
Serial.begin(115200);
//Setup all my sensors, code not relevant
//Connect Wifi
ssid_string = "DRILL_" + String(chip_id);
ssid_string.toCharArray(ssid, 500);
SetupWifi(ssid);
}
void loop(void) {
//B. <<<< SO THIS IS THE PART IN THE LOOP THAT IS NOT WORKING
int packetSize = UDP.parsePacket();
packetSize = UDP.parsePacket();
if (packetSize) {
Serial.println("");
Serial.print("Received packet");
// read the packet into packetBufffer
UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
int value = packetBuffer[0] * 256 + packetBuffer[1];
Serial.println(value);
}
//Read out all my sensors, code not relevant, paste all sensor data in one string
//SendString over serial
Serial.print(SendString);
SendIntervalUDP(1); // Send SendString over UDP every x measurements (see function below)
//Listen to serial
if (Serial.available() > 0) {
String Received = Serial.readString();
Serial.println("ESP received: " + Received);
}
}
下面是设置wifi和通过wifi发送数据的一些支持功能
unsigned long previousWifiStatMillis;
//Connect wifi during setup
void SetupWifi(char my_ssid[]) {
// WiFi init
wifiConnected = createAP(my_ssid);
udpConnected = connectUDP();
// Wait for first packet
Serial.println("Waiting for start");
//A. <<<< SO THIS IS THE PART IN THE CODE THAT IS ACTUALLY WORKING
int packetSize = UDP.parsePacket();
while (packetSize < 1) {
packetSize = UDP.parsePacket();
yield(); // Allow the background functions to work
//Listen to serial
if (Serial.available() > 0) {
String Received = Serial.readString();
Serial.println("I received: " + Received);
if (Received.substring(0) == "S") {
Serial.println("Starting..");
break;
}
}
if (packetSize)
{
Serial.println("");
Serial.print("Received packet");
// read the packet into packetBufffer
UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
int value = packetBuffer[0] * 256 + packetBuffer[1];
Serial.println(value);
}
}
}
// connect to UDP – returns true if successful or false if not
boolean connectUDP() {
boolean state = false;
Serial.println("");
Serial.println("Connecting to UDP");
if (UDP.begin(localPort) == 1) {
Serial.println("Connection successful");
state = true;
}
else {
Serial.println("Connection failed");
}
return state;
}
// connect to wifi – returns true if successful or false if not
boolean createAP(char my_ssid[]) {
boolean state = true;
int i = 0;
WiFi.softAP(my_ssid, password); // Start the access point
WiFi.mode(WIFI_AP);
Serial.print("Access Point \"");
Serial.print(my_ssid);
Serial.println("\" started");
Serial.print("IP address:\t");
Serial.println(WiFi.softAPIP()); // Send the IP address of the ESP8266 to the computer
state = true;
return state;
}
// connect to wifi – returns true if successful or false if not
boolean connectWifi(char my_ssid[]) {
boolean state = true;
int i = 0;
WiFi.begin(my_ssid, password);
Serial.println("");
Serial.println("Connecting to WiFi");
// Wait for connection
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if (i > 20) {
state = false;
break;
}
i++;
}
if (state) {
Serial.println("");
Serial.print("Connected to ");
Serial.println(my_ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
else {
Serial.println("");
Serial.println("Connection failed.");
}
return state;
}
void SendIntervalUDP(int interval) {
//Send an udp packet every x packets with x the interval
j++;
if (j > (interval-1) ) {
j = 0;
//SendString over wifi
if (wifiConnected) {
if (udpConnected) {
// send a reply, to predetermined hotspot
UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
SendBuffer.toCharArray(ReplyBuffer, 500);
UDP.write(ReplyBuffer);
UDP.endPacket();
}
}
SendBuffer = "";
}
}
"Generic Class" 中的 WiFi 事件适用于传输层以下的 OSI 级别。 TCP 和 UDP 是传输层。
要接收 UDP 数据包,您必须在 loop()
中调用 UDP.parsePacket();
(或在从 loop()
调用的函数中),就像所有其他实现 Arduino [=13= 的 Arduino 网络库一样]基地class.
如果数据包可用,调用 parsePacket
将数据包读入内部缓冲区并 returns 数据包的大小。下一次调用 parsePacket
会清除缓冲区并在可用时用新数据包填充它。您调用 parsePacket
两次,第二次总是 returns 什么都没有。