Arduino ESP8266 Softwareserial没有足够的缓冲区大小用于HTTP获取请求

4Ja*_*eka 2 c arduino esp8266

我正在一个项目中使用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() );
  }
}
Run Code Online (Sandbox Code Playgroud)

我成功打开了与服务器的TCP连接,发送了一个较长的GET请求(超过600个字符),并通过SoftwareSerial read()函数处理了所有较长的响应,并将它们全部打印到串行监视器中。简而言之,此代码可以处理服务器的600多个char响应,即:

在此处输入图片说明

目的是通过“ 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++] = '\0';
    Serial.println(response);
    for (i = 0; i < 625; i++) {
      response[i] = '\0';
    }

    ESPserial.println("AT+CIPSEND=107");
    delay(5000);

    i = 0;
    while ( ESPserial.available() ) {
      response[i] = ESPserial.read();
      i++;
    }
    response[i++] = '\0';
    Serial.println(response);
    for (i = 0; i < 625; i++) {
      response[i] = '\0';
    }

    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++] = '\0';
    Serial.println(response);
    for (i = 0; i < 625; i++) {
      response[i] = '\0';
    }
}
void loop() {
  // put your main code here, to run repeatedly:

}
Run Code Online (Sandbox Code Playgroud)

它在“ setup()”作用域的末尾之前打印响应。让我也把输出的照片放进去:

在此处输入图片说明

总之,问题在于:SoftwareSerial具有64字节的缓冲区,可以增加到256字节,当我增加它时,程序这次可以打印256个字符,但是,在我的第一个代码中,我手动发送了AT命令,尽管它有64个字节的缓冲区,但它仍可以处理整个响应,并且可以将其打印到串行监视器上。在第二个中,我无法处理整个响应并将其存储到char数组中。

我希望我能解释我的问题,并指出我在流程中的确切位置以及细节。

你建议我做什么。处理这个大响应并将其放入字符数组时,我该怎么办?我如何处理整个响应,该响应最初保留在ESP8266ex的缓冲区上,并通过SoftwareSerial类由Arduino RX引脚读取,其中read()函数具有64个字节的数组,最多可以增加到256个,但不能再增加了?

Daw*_*ion 5

因此,这里的问题只在于时间安排。您知道对软件串行的缓冲区大小有一个限制(对于任何硬件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);
Run Code Online (Sandbox Code Playgroud)

现在,您想要修改此代码以使其在收到所有期望的数据时结束。此外,这种简单的设置将响应的最大大小限制为1023字节,这也不太有用。理想情况下,您将继续阅读,直到找到HTTP正文为止,然后丢弃其他所有内容,这意味着查找数据的缓冲区很小,而实际存储正文的缓冲区可能更大。