尝试在自定义 class 中使用 NTPClient 时出现异常 (ESP8266)
Getting an exception when try to use NTPClient in a custom class (ESP8266)
当我尝试在自定义 class RealTimeService 中使用 NTPClient 时出现异常(见下文)。请告知为什么以及如何解决它。谢谢。
文件RealTimeService.h:
#ifndef RealTimeLib
#define RealTimeLib
#include <NTPClient.h>
#include <WiFiUdp.h>
class RealTimeService {
private:
NTPClient _ntp;
NTPClient _createNtpClient();
void _update();
public:
RealTimeService();
void begin();
};
#endif
文件RealTimeService.cpp:
#include "RealTimeService.h"
RealTimeService::RealTimeService() :
_ntp(_createNtpClient())
{
}
NTPClient RealTimeService::_createNtpClient() {
WiFiUDP udp;
NTPClient ntp(udp, "pool.ntp.org", 3600, 86400000);
return ntp;
}
void RealTimeService::begin() {
_update();
}
void RealTimeService::_update() {
_ntp.begin(); // Throws an exception
if(_ntp.update()) {
long time = _ntp.getEpochTime();
} else {
Serial.print("Failed to get time from server.\n");
}
}
文件WebServerSecure.ino:
#include <ESP8266WiFi.h>
#include "RealTimeService.h"
#ifndef STASSID
#define STASSID "Sedmikraska"
#define STAPSK "38098246"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
RealTimeService realTime;
void setup(void) {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
realTime.begin();
}
void loop(void) {
delay(1000);
}
它在第 _ntp.begin() 行的函数 RealTimeService::_update() 中抛出异常;
User exception (panic/abort/assert)
解码后的栈是:
0x4020714a: HardwareSerial::begin(unsigned long, SerialConfig, SerialMode, unsigned char, bool) at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\HardwareSerial.cpp line 51
0x4020804c: __unhandled_exception_cpp() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\core_esp8266_main.cpp line 229
0x4020a07c: NTPClient::begin(int) at C:\Users\user\Documents\Arduino\libraries\NTPClient\NTPClient.cpp line 61
0x40202544: NTPClient::begin() at C:\Users\user\Documents\Arduino\libraries\NTPClient\NTPClient.cpp line 53
0x40201028: RealTimeService::_update() at C:\Users\user\AppData\Local\Temp\arduino_build_506039\sketch\RealTimeService.cpp line 20
0x40201b04: ESP8266WiFiSTAClass::status() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\libraries\ESP8266WiFi\src\ESP8266WiFiSTA.cpp line 634
0x40201058: RealTimeService::begin() at C:\Users\user\AppData\Local\Temp\arduino_build_506039\sketch\RealTimeService.cpp line 16
0x4020115c: setup() at C:\Users\user\Documents\Arduino\WebServerSecure/WebServerSecure.ino line 23
0x40208224: loop_wrapper() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\core_esp8266_main.cpp line 194
您在 RealTimeService::_createNtpClient()
中定义 udp
并将其传递给 NTPClient
。 NTPClient
在RealTimeService::_createNtpClient()
returns之后还会继续需要,但是udp
就失效了。即使 NTPClient
复制它,它的析构函数也会被调用,使它使用的资源失效。
您需要将 udp
更改为实例变量,这样它就可以在 _ntp
存在时继续存在。
class RealTimeService {
private:
WiFiUDP _udp;
NTPClient _ntp;
...
和
NTPClient RealTimeService::_createNtpClient() {
NTPClient ntp(_udp, "pool.ntp.org", 3600, 86400000);
您的代码也在重复调用 _ntp.begin()
。您应该确保您使用的 NTP 库允许这样做;有时库被编写成它们的 begin()
方法只能被调用一次。
除了 @romkey 的回答之外,您可以完全跳过 _createNtpClient
并在构造函数中移动字段的初始化。更紧凑的东西,比如
#ifndef RealTimeLib
#define RealTimeLib
#include <WiFiUdp.h>
#include <NTPClient.h>
class RealTimeService {
private:
WiFiUDP _udp;
NTPClient _ntp;
...
public:
RealTimeService();
...
};
#endif
#include "RealTimeService.h"
RealTimeService::RealTimeService() :
_udp(),
_ntp(_udp, "pool.ntp.org", 3600, 86400000)
{
}
...
当我尝试在自定义 class RealTimeService 中使用 NTPClient 时出现异常(见下文)。请告知为什么以及如何解决它。谢谢。
文件RealTimeService.h:
#ifndef RealTimeLib
#define RealTimeLib
#include <NTPClient.h>
#include <WiFiUdp.h>
class RealTimeService {
private:
NTPClient _ntp;
NTPClient _createNtpClient();
void _update();
public:
RealTimeService();
void begin();
};
#endif
文件RealTimeService.cpp:
#include "RealTimeService.h"
RealTimeService::RealTimeService() :
_ntp(_createNtpClient())
{
}
NTPClient RealTimeService::_createNtpClient() {
WiFiUDP udp;
NTPClient ntp(udp, "pool.ntp.org", 3600, 86400000);
return ntp;
}
void RealTimeService::begin() {
_update();
}
void RealTimeService::_update() {
_ntp.begin(); // Throws an exception
if(_ntp.update()) {
long time = _ntp.getEpochTime();
} else {
Serial.print("Failed to get time from server.\n");
}
}
文件WebServerSecure.ino:
#include <ESP8266WiFi.h>
#include "RealTimeService.h"
#ifndef STASSID
#define STASSID "Sedmikraska"
#define STAPSK "38098246"
#endif
const char* ssid = STASSID;
const char* password = STAPSK;
RealTimeService realTime;
void setup(void) {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
realTime.begin();
}
void loop(void) {
delay(1000);
}
它在第 _ntp.begin() 行的函数 RealTimeService::_update() 中抛出异常;
User exception (panic/abort/assert)
解码后的栈是:
0x4020714a: HardwareSerial::begin(unsigned long, SerialConfig, SerialMode, unsigned char, bool) at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\HardwareSerial.cpp line 51
0x4020804c: __unhandled_exception_cpp() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\core_esp8266_main.cpp line 229
0x4020a07c: NTPClient::begin(int) at C:\Users\user\Documents\Arduino\libraries\NTPClient\NTPClient.cpp line 61
0x40202544: NTPClient::begin() at C:\Users\user\Documents\Arduino\libraries\NTPClient\NTPClient.cpp line 53
0x40201028: RealTimeService::_update() at C:\Users\user\AppData\Local\Temp\arduino_build_506039\sketch\RealTimeService.cpp line 20
0x40201b04: ESP8266WiFiSTAClass::status() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\libraries\ESP8266WiFi\src\ESP8266WiFiSTA.cpp line 634
0x40201058: RealTimeService::begin() at C:\Users\user\AppData\Local\Temp\arduino_build_506039\sketch\RealTimeService.cpp line 16
0x4020115c: setup() at C:\Users\user\Documents\Arduino\WebServerSecure/WebServerSecure.ino line 23
0x40208224: loop_wrapper() at C:\Users\user\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266.7.4\cores\esp8266\core_esp8266_main.cpp line 194
您在 RealTimeService::_createNtpClient()
中定义 udp
并将其传递给 NTPClient
。 NTPClient
在RealTimeService::_createNtpClient()
returns之后还会继续需要,但是udp
就失效了。即使 NTPClient
复制它,它的析构函数也会被调用,使它使用的资源失效。
您需要将 udp
更改为实例变量,这样它就可以在 _ntp
存在时继续存在。
class RealTimeService {
private:
WiFiUDP _udp;
NTPClient _ntp;
...
和
NTPClient RealTimeService::_createNtpClient() {
NTPClient ntp(_udp, "pool.ntp.org", 3600, 86400000);
您的代码也在重复调用 _ntp.begin()
。您应该确保您使用的 NTP 库允许这样做;有时库被编写成它们的 begin()
方法只能被调用一次。
除了 @romkey 的回答之外,您可以完全跳过 _createNtpClient
并在构造函数中移动字段的初始化。更紧凑的东西,比如
#ifndef RealTimeLib
#define RealTimeLib
#include <WiFiUdp.h>
#include <NTPClient.h>
class RealTimeService {
private:
WiFiUDP _udp;
NTPClient _ntp;
...
public:
RealTimeService();
...
};
#endif
#include "RealTimeService.h"
RealTimeService::RealTimeService() :
_udp(),
_ntp(_udp, "pool.ntp.org", 3600, 86400000)
{
}
...