Arduino ESP8266 Softwareserial 没有足够的缓冲区大小用于 HTTP get 请求
Arduino ESP8266 Softwareserial not enough buffer size for HTTP get request
我正在做一个项目,我在其中使用 arduino uno 和 ESP8266ex 作为 wifi 模块。电线连接数:
Arduino 5V --> 3.3V 稳压器 --> ESP:CH_PD(带 10k 电阻)和 VCC Arduino GND --> 3.3V 稳压器 --> ESP:GND 和 RST(复位已连接)通过按钮和电阻)Arduino RX --> ESP TX Arduino TX --> 分压器(2k 1k 电阻)--> ESP RX 5uF 电容器 --> 稳压器以防止 ESP 自行复位。
现在让我解释一下我遇到的问题。我有两个代码在使用 ESP8266 作为 arduino uno 的 wifi 模块。在我的第一个程序中,我手动发送命令:
#define ard_rx_esp_tx 2
#define ard_tx_esp_rx 3
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX
void setup()
{
int i = 0;
Serial.begin(9600); // communication with the host computer
while (!Serial);
// Start the software serial for communication with the ESP8266
ESPserial.begin(9600);
Serial.println("");
Serial.println(F("Remember to to set Both NL & CR in the serial monitor."));
Serial.println(F("Ready"));
Serial.println(F(""));
Serial.println(F("start"));
delay(1000);
}
void loop()
{
if ( ESPserial.available() ) {
char c = ESPserial.read();
Serial.print(c);
}
if ( Serial.available() ) {
ESPserial.write( Serial.read() );
}
}
我成功地打开了与服务器的 TCP 连接,发送了一个长(超过 600 个字符)的 GET 请求,并通过 SoftwareSerial read() 函数处理了所有长响应并将它们全部打印到串行监视器。简而言之,这段代码可以处理服务器的 600+ 个字符响应:
目的是通过"SoftwareSerial.print()"发送这些AT命令,并将整个响应放在一个字符数组中以解析其API-KEY。到目前为止我为此编写的代码:
#define ard_rx_esp_tx 2
#define ard_tx_esp_rx 3
char response[625];
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX
int i;
void setup()
{
Serial.begin(9600); // communication with the host computer
while (!Serial);
// Start the software serial for communication with the ESP8266
ESPserial.begin(9600);
Serial.println("");
Serial.println(F("Remember to to set Both NL & CR in the serial monitor."));
Serial.println(F("Ready"));
Serial.println(F(""));
Serial.println(F("start"));
delay(1000);
ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
ESPserial.println("AT+CIPSEND=107");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
ESPserial.println("GET request to the server which has length 107 as indicated");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
}
void loop() {
// put your main code here, to run repeatedly:
}
它在 "setup()" 范围的末尾之前打印响应。让我也放上输出的照片:
总而言之,问题是:SoftwareSerial 有 64 字节缓冲区,可以增加到 256 字节,当我增加它时,程序这次能够打印 256 个字符,但是,在我的第一个代码中,其中我手动发送 AT 命令,它可以处理整个响应,尽管它有 64 字节缓冲区,并且能够将它打印到串行监视器。在第二个中,我无法处理并将整个响应存储到一个字符数组中。
我希望我能解释我的问题,并详细指出我在流程中的确切位置。
你建议我做什么。在处理这个大响应并将其放入字符数组时我能做什么?我如何处理最初保留在 ESP8266ex 缓冲区上并通过 SoftwareSerial class 由 Arduino RX 引脚读取的整个响应,其中函数 read() 具有 64 字节数组并且可以增加到 256 但不能更多?
所以,这里的问题全在于时机。您知道您对软件串行的缓冲区大小有限制(对于任何硬件 UART 也是如此),即 256 字节,波特率为每秒 9600 位。
由于有一个起始位、8 个数据位和一个停止位(假设您在这里使用 9600 8N1,因为它是最常见的),您将每隔 (1 / 9600) * 10 接收一个字节的数据- 秒,或 1.04 毫秒。因此,要接收 256 个字节,大约需要 266 毫秒。这意味着在 266 毫秒后,您的缓冲区将完全填满,之后您收到的任何内容都将开始删除之前收到的数据。
这就是问题的症结所在 - 您正在向 ESP 发送命令以从服务器接收数据,然后休眠 5 秒钟,这意味着没有任何内容会从缓冲区中提取数据,因此它环绕,导致数据丢失。串行缓冲区的要点不是保存您将在一个点接收到的整个数据集,而是保存它足够长的时间直到您可以读出它,这就是为什么它们通常很小的原因。
您需要做的是发送命令,并让您的 Arduino 立即 运行 代码以尽可能快的速度从缓冲区检索数据,直到它找到预期的结束或超时。
像这样基本的东西会让你继续:
char espBuffer[1024] = {0};
int readCount = 0;
long startTime = millis();
ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80");
while (millis() - startTime < 5000) { // Run for at least 5 seconds
// Check to make sure we don't exceed espBuffer's boundaries
if (ESPserial.available() > readCount + sizeof espBuffer - 1)
break;
readCount += ESPserial.readBytes(espBuffer + readCount, ESPserial.available());
}
Serial.println(espBuffer);
现在,您需要修改此代码,使其在收到所有预期数据后结束。此外,这个简单的设置将响应的最大大小限制为 1023 字节,这也不是很有帮助。理想情况下,您会继续阅读,直到找到 HTTP 正文,然后丢弃其他所有内容,这意味着查找数据的缓冲区很小,而实际存储正文的缓冲区可能更大。
我正在做一个项目,我在其中使用 arduino uno 和 ESP8266ex 作为 wifi 模块。电线连接数:
Arduino 5V --> 3.3V 稳压器 --> ESP:CH_PD(带 10k 电阻)和 VCC Arduino GND --> 3.3V 稳压器 --> ESP:GND 和 RST(复位已连接)通过按钮和电阻)Arduino RX --> ESP TX Arduino TX --> 分压器(2k 1k 电阻)--> ESP RX 5uF 电容器 --> 稳压器以防止 ESP 自行复位。
现在让我解释一下我遇到的问题。我有两个代码在使用 ESP8266 作为 arduino uno 的 wifi 模块。在我的第一个程序中,我手动发送命令:
#define ard_rx_esp_tx 2
#define ard_tx_esp_rx 3
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX
void setup()
{
int i = 0;
Serial.begin(9600); // communication with the host computer
while (!Serial);
// Start the software serial for communication with the ESP8266
ESPserial.begin(9600);
Serial.println("");
Serial.println(F("Remember to to set Both NL & CR in the serial monitor."));
Serial.println(F("Ready"));
Serial.println(F(""));
Serial.println(F("start"));
delay(1000);
}
void loop()
{
if ( ESPserial.available() ) {
char c = ESPserial.read();
Serial.print(c);
}
if ( Serial.available() ) {
ESPserial.write( Serial.read() );
}
}
我成功地打开了与服务器的 TCP 连接,发送了一个长(超过 600 个字符)的 GET 请求,并通过 SoftwareSerial read() 函数处理了所有长响应并将它们全部打印到串行监视器。简而言之,这段代码可以处理服务器的 600+ 个字符响应:
目的是通过"SoftwareSerial.print()"发送这些AT命令,并将整个响应放在一个字符数组中以解析其API-KEY。到目前为止我为此编写的代码:
#define ard_rx_esp_tx 2
#define ard_tx_esp_rx 3
char response[625];
#include <SoftwareSerial.h>
SoftwareSerial ESPserial(ard_rx_esp_tx, ard_tx_esp_rx); // RX | TX
int i;
void setup()
{
Serial.begin(9600); // communication with the host computer
while (!Serial);
// Start the software serial for communication with the ESP8266
ESPserial.begin(9600);
Serial.println("");
Serial.println(F("Remember to to set Both NL & CR in the serial monitor."));
Serial.println(F("Ready"));
Serial.println(F(""));
Serial.println(F("start"));
delay(1000);
ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
ESPserial.println("AT+CIPSEND=107");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
ESPserial.println("GET request to the server which has length 107 as indicated");
delay(5000);
i = 0;
while ( ESPserial.available() ) {
response[i] = ESPserial.read();
i++;
}
response[i++] = '[=11=]';
Serial.println(response);
for (i = 0; i < 625; i++) {
response[i] = '[=11=]';
}
}
void loop() {
// put your main code here, to run repeatedly:
}
它在 "setup()" 范围的末尾之前打印响应。让我也放上输出的照片:
总而言之,问题是:SoftwareSerial 有 64 字节缓冲区,可以增加到 256 字节,当我增加它时,程序这次能够打印 256 个字符,但是,在我的第一个代码中,其中我手动发送 AT 命令,它可以处理整个响应,尽管它有 64 字节缓冲区,并且能够将它打印到串行监视器。在第二个中,我无法处理并将整个响应存储到一个字符数组中。
我希望我能解释我的问题,并详细指出我在流程中的确切位置。
你建议我做什么。在处理这个大响应并将其放入字符数组时我能做什么?我如何处理最初保留在 ESP8266ex 缓冲区上并通过 SoftwareSerial class 由 Arduino RX 引脚读取的整个响应,其中函数 read() 具有 64 字节数组并且可以增加到 256 但不能更多?
所以,这里的问题全在于时机。您知道您对软件串行的缓冲区大小有限制(对于任何硬件 UART 也是如此),即 256 字节,波特率为每秒 9600 位。
由于有一个起始位、8 个数据位和一个停止位(假设您在这里使用 9600 8N1,因为它是最常见的),您将每隔 (1 / 9600) * 10 接收一个字节的数据- 秒,或 1.04 毫秒。因此,要接收 256 个字节,大约需要 266 毫秒。这意味着在 266 毫秒后,您的缓冲区将完全填满,之后您收到的任何内容都将开始删除之前收到的数据。
这就是问题的症结所在 - 您正在向 ESP 发送命令以从服务器接收数据,然后休眠 5 秒钟,这意味着没有任何内容会从缓冲区中提取数据,因此它环绕,导致数据丢失。串行缓冲区的要点不是保存您将在一个点接收到的整个数据集,而是保存它足够长的时间直到您可以读出它,这就是为什么它们通常很小的原因。
您需要做的是发送命令,并让您的 Arduino 立即 运行 代码以尽可能快的速度从缓冲区检索数据,直到它找到预期的结束或超时。
像这样基本的东西会让你继续:
char espBuffer[1024] = {0};
int readCount = 0;
long startTime = millis();
ESPserial.println("AT+CIPSTART=\"TCP\",\"domainname\",80");
while (millis() - startTime < 5000) { // Run for at least 5 seconds
// Check to make sure we don't exceed espBuffer's boundaries
if (ESPserial.available() > readCount + sizeof espBuffer - 1)
break;
readCount += ESPserial.readBytes(espBuffer + readCount, ESPserial.available());
}
Serial.println(espBuffer);
现在,您需要修改此代码,使其在收到所有预期数据后结束。此外,这个简单的设置将响应的最大大小限制为 1023 字节,这也不是很有帮助。理想情况下,您会继续阅读,直到找到 HTTP 正文,然后丢弃其他所有内容,这意味着查找数据的缓冲区很小,而实际存储正文的缓冲区可能更大。