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 正文,然后丢弃其他所有内容,这意味着查找数据的缓冲区很小,而实际存储正文的缓冲区可能更大。