我对以太网世界还很陌生。因此,如果我提出愚蠢的问题,请多多包涵。
我使用 Atmega328P+ENC28J60 芯片设计了一个 PCB(原理图附在下图中 - sch1、sch2)。该板的功能基本上是向服务器发送 GET 请求并检索一组 json 数据以打开输出引脚,因此根据我的理解,我的板仅充当客户端,对吗?代码附在下面:
#include <EEPROM.h>
#include <ArduinoJson.h>
#include <EthernetENC.h>
#define OUT0 2
#define OUT1 A3
#define OUT2 A2
#define OUT3 A1
#define OUT4 A0
#define OUT5 9
#define OUT6 8
#define OUT7 7
#define OUT8 6
#define OUT9 5
#define CS 10
// mac: 46 57 5a 6b 48 51
#define HOSTNAME "autolighting.afa-sports.com"
#define ID_SIZE 6
static byte mac[ID_SIZE];
static char macBuffer[ID_SIZE*2+1];
const byte output[] PROGMEM = {OUT0, OUT1, OUT2, OUT3, OUT4, OUT5, OUT6, OUT7, OUT8, OUT9};
EthernetClient client;
void clientRead() {
StaticJsonDocument<40> filter;
StaticJsonDocument<120> doc;
filter.clear();
doc.clear();
filter["data"]["relay_actions"] = true;
client.find("\r\n\r\n");
deserializeJson(doc, client, DeserializationOption::Filter(filter));
client.flush();
delay(50);
if (!doc["data"]["relay_actions"].isNull()) {
for (byte i = 0; i < 10; i++) {
// Serial.print(doc["data"]["relay_actions"][i].as<bool>());
digitalWrite(pgm_read_byte_near(&output[i]), doc["data"]["relay_actions"][i].as<bool>());
}
// Serial.println();
}
filter.clear();
doc.clear();
}
void sendReq() {
client.println(F("GET /api/iot/master-controller/get-command HTTP/1.1"));
client.println(F("Host: autolighting.afa-sports.com"));
// client.println(F("DEVICE-ID: 46575a6b4851"));
client.print(F("DEVICE-ID: "));
client.println(macBuffer);
client.println(F("Connection: close"));
client.println();
}
void setup() {
Serial.begin(115200);
for (byte i = 0; i < 10; i++) {
pinMode(pgm_read_byte_near(&output[i]), OUTPUT);
digitalWrite(pgm_read_byte_near(&output[i]), LOW);
}
for (uint8_t i = 0; i < ID_SIZE; i++) {
byte charByte = EEPROM.read(i);
if (charByte != 0) {
char temp[2];
mac[i] = charByte;
itoa(mac[i], temp, 16);
strcat(macBuffer, strlwr(temp)); // REMOVE strlwr IN RELEASE VERSION
free(temp);
delay(10);
}
}
strcat(macBuffer, '\0');
Ethernet.init(CS);
while (!Ethernet.begin(mac));
client.setTimeout(5000);
delay(1000);
}
void loop() {
while (!Ethernet.begin(mac)); // init fail
delay(1000);
if (client.connect(HOSTNAME, 80)) {
sendReq();
clientRead();
client.stop();
}
delay(3000);
}
由于 SRAM 消耗量大,而且我将来可能还有其他东西(还不确定)要添加到开发板上,我尝试通过更改此设置(在 uipethernet-conf.h 文件中)来最小化动态内存):
#define UIP_SOCKET_NUMPACKETS 5
#define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_UDP_CONNS 4
为此:
#define UIP_SOCKET_NUMPACKETS 2
#define UIP_CONF_MAX_CONNECTIONS 2
#define UIP_CONF_UDP_CONNS 1
我想知道这会影响系统性能吗?顺便说一句,我还将超时设置为 5 秒
经过 13 小时的平稳运行后,电路板死机,只有在我硬重置电路板时才恢复正常。目前,我正在将电路板连接到无线扩展器,因为我没有坐在 wifi 路由器旁边。在我看来这像是一个内存泄漏问题,但内存泄漏问题是否仍然存在于最新的 ArduinoJson 和 EthernetENC/UIPEthernet 库中?
P/S: 之前用的是UIPEthernet.h,后来有人指导我试用了EthernetENC库,内存消耗确实下降了一些,但是卡顿问题依旧存在
请随时指出我犯的任何错误,仍在学习冒险中。 =) 非常感谢您的帮助。非常感谢。
库版本:
- ArduinoJson 6.17.2
- 以太网ENC 2.0.0
- UIPEthernet 2.0.9
最佳答案
没有这些硬件,只能根据您的代码和 Arduino 引用进行分析。
来自您的代码
while (!Ethernet.begin(mac)); // init fail
在以下情况下“可能”导致卡住:
- Ethernet.begin 总是返回 false
- Ethernet.begin“可以”调用多次吗?
这些是一些可能有帮助的引用:
Arduino DHCP failed to configure
根据维基:
https://github.com/jandrassy/EthernetENC/wiki/Examples
你应该使用:
以太网.maintain();
client.available();
编写自己的延迟函数:
void mDelay(unsigned long milliseconds) {
const unsigned d = 1;
while (milliseconds > d) {
Ethernet.maintain();
delay(d);
milliseconds -= d;
}
Ethernet.maintain();
delay(milliseconds);
}
注意:对于 arduino 或电子产品问题,可能是 https://electronics.stackexchange.com/ 是一个更合适的网站。
关于c++ - atmega328P+ENC28J60运行12小时卡死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64896657/