Arduino ESP8266 Softwareserial не хватает размера буфера для HTTP-запроса на получение

Я работаю над проектом, в котором использую arduino uno и ESP8266ex в качестве модуля Wi-Fi. Подключения проводов:

Arduino 5V -> Регулятор 3,3 В -> ESP: CH_PD (с резистором 10 кОм) и VCC Arduino GND -> Регулятор 3,3 В -> ESP: GND и RST (сброс подключается через кнопку и сопротивление) Arduino RX - -> ESP TX Arduino TX -> Делитель напряжения (резисторы 2 кОм по 1 кОм) -> Конденсатор ESP RX 5 мкФ -> Стабилизатор напряжения для предотвращения самовосстановления ESP.

Теперь позвольте мне объяснить мою проблему. У меня работают два кода, на которых я использую ESP8266 в качестве модуля Wi-Fi для arduino uno. В своей первой программе я отправлял команды вручную:

#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-соединение с сервером, отправить запрос GET, который имеет длинный (более 600 символов), обработать весь длинный ответ с помощью функции SoftwareSerial read () и распечатать их все на последовательном мониторе. Короче говоря, этот код может обрабатывать 600+ символьных ответов сервера, которые:

введите описание изображения здесь

Цель состоит в том, чтобы отправить эти AT-команды через «SoftwareSerial.print ()» и поместить весь ответ в массив символов для анализа его 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:

}

Что печатает ответ раньше, в конце области «setup ()». Разрешите еще выложить фото выхода:

введите описание изображения здесь

В заключение проблема заключается в том, что: SoftwareSerial имеет 64-байтовый буфер, который может быть увеличен до 256 байтов, и когда я увеличиваю его, программа может напечатать 256 символов на этот раз, однако в моем первом коде, в котором я отправлял AT-команды вручную , он может обрабатывать весь ответ, несмотря на свой 64-байтовый буфер, и может распечатать его на последовательном мониторе. Во втором я не смог обработать и сохранить весь ответ в массиве символов.

Я надеюсь, что смогу объяснить свою проблему и подробно указать, где именно я нахожусь в процессе.

Что вы предлагаете мне делать? Что я могу сделать, обрабатывая этот большой ответ и помещая его в массив символов? Как я могу обработать весь ответ, который изначально остается в буфере ESP8266ex и читается выводом Arduino RX через класс SoftwareSerial, в котором функция read () имеет массив размером 64 байта и может быть увеличена до 256, но не более?


person 4JaoDeka    schedule 14.07.2016    source источник


Ответы (1)


Итак, проблема здесь во времени. Вы знаете, что у вас есть ограничение на размер буфера для программного последовательного порта (что также верно и для любого аппаратного 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, и отбросите все остальное, что означает, что буфер для поиска данных небольшой, а буфер для фактического хранения тела может быть намного больше.

person Dawn Minion    schedule 14.07.2016