Arduino (ESP8266) не получает всех символов

#arduino-ide #arduino-esp8266

#arduino-ide #arduino-esp8266

Вопрос:

У меня есть файл в 18164 байта, который я пытаюсь загрузить с ESP8266 (4m), но я получаю только часть файла (около 17000 байт). Иногда он получит все, но чаще всего этого не произойдет. Файл представляет собой уменьшенный файл javascript. Файлы меньшего размера по 5000 байт работают нормально. Если размер буфера является проблемой, как мне увеличить размер буфера для WiFiClient?

 void setup()
{
  String line = "";
  ...

  while ((net.connected() || net.available()))
  {
    if (net.available())
    {
      char c = net.read();
      line  = c;
    }
  }
  net.stop();

  Serial.println("Line:-"   line   "-");
}

void loop() {
}
  

Ответ №1:

Вероятно, вы исчерпываете доступную память в вашем ESP8266. Начать не с чего.

Ваш 4m ESP8266 имеет 4 Мбита флэш-памяти (512 КБ), но вы накапливаете загружаемый файл в оперативной памяти, которой гораздо меньше. ESP8266 имеет 80 КБ оперативной памяти. Часть этой оперативной памяти уже будет использоваться ядром Arduino и сетевым стеком.

Я загрузил минимальную программу на ESP8266 с подключенным клиентом Wi-Fi и увидел 51 КБ доступной оперативной памяти.

Вы также много используете String . String сохраняет саму фактическую строку, используя память, выделенную из свободной памяти на ESP8266. Каждый раз, когда вы добавляете символ, String освобождается его предыдущее хранилище и выделяется тот же объем плюс на один байт больше. Ядро Arduino не обладает особенно сложным управлением памятью; это может привести к фрагментации кучи до такой степени, что вы просто не сможете выделить больший фрагмент памяти, и ваша программа завершится сбоем.

Вы можете узнать о состоянии свободной памяти с помощью этих вызовов:

  • ESP.getFreeHeap() — возвращает общий объем доступной памяти
  • ESP.getHeapFragmentation() — возвращает указание на то, насколько сильно фрагментирована куча. Чем больше, тем хуже — более 50 — это очень плохо.
  • ESP.getMaxFreeBlockSize() — самый большой блок, который вы можете выделить.

Чтобы проверить, я бы попробовал что-то вроде этого:

 while ((net.connected() || net.available()))
  {
    if (net.available())
    {
      char c = net.read();
      line  = c;
      Serial.print("line length: ");
      Serial.println(line.length());
      Serial.print("free heap: ");
      Serial.println(ESP.getFreeHeap());
      Serial.print("heap fragmentation: ");
      Serial.println(ESP.getHeapFragmentation());
      Serial.print("max block size: ");
      Serial.println(ESP.getMaxFreeBlockSize());
    }
  }
  net.stop();
  

Если максимальный размер блока становится близким к или меньше длины line , вы больше не сможете выделить достаточно большой фрагмент памяти для хранения line c , и ваша программа завершится сбоем, как вы описали.

Единственное, что вы могли бы попробовать, это использовать reserve() метод в String после создания строки. Что-то вроде:

 String line;

line.reserve(18500);
line = "";
  

В конечном счете, вам гораздо лучше одновременно считывать ваш файл в char массив или сохранять его в виде фрагментов (512 было бы хорошим размером), чем использовать String .