Загрузка файла с SD-карты приводит к зависанию ESP-12E

Я использую ESP8266 Arduino для компиляции и загрузки своего кода в NodeMCU 1.0 (модуль ESP-12E). Размер вспышки: 4M (3M SPIFFS) Частота процессора: 80 МГц Скорость загрузки: 115200

Я использую портативную версию arduino-1.6.9-windows, извлечённую на диск D:. Я использую последний образ Arduino для ESP8266, полученный командой git.

Я написал этот базовый код для загрузки файла «datalog.txt» (хранящегося в корне моей SD-карты).

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "<h1>Hello! from ESP8266!</h1>"
                "<p><a href=\"down\"><button>Download</button></a>";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: ");
    Serial.println(fsizeDisk);

    size_t fsizeSent = server.streamFile(dataFile,"text/plain");

    Serial.print("fsizeSent: ");
    Serial.println(fsizeSent);

    dataFile.close();
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // проверяем, присутствует ли карта и можно ли ее инициализировать:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // больше ничего не делаем:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}

Но когда я нажимаю кнопку «Загрузить», ESP зависает, выдает несколько ошибок, а затем перезапускается, как показано ниже (из моего последовательного монитора):

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600

Panic D:\arduino-1.6.9-windows\arduino-1.6.9\hardware\esp8266com\esp8266\cores\esp8266\core_esp8266_main.cpp:98 __yield

ctx: sys 
sp: 3ffffc80 end: 3fffffb0 offset: 01b0

>>>stack>>>
3ffffe30:  3ffefdf4 000003b9 000003b9 4010020c  
3ffffe40:  00000000 3ffe9645 00000001 4020815d  
3ffffe50:  3ffefdf4 00000481 3fff0d50 402077e5  
3ffffe60:  3fff337c 00000b68 00000000 40207823  
3ffffe70:  3fff3a74 3fff1480 3fff3a74 3fff1474  
3ffffe80:  3fff337c 00000b68 3fff307c 40202a57  
3ffffe90:  3fff3a74 00000b68 3fff2cfc 40202c07  
3ffffea0:  00000000 3ffe9704 3fff337c 3fff1474  
3ffffeb0:  3fff337c 3fff147c 3fff2cfc 40202d34  
3ffffec0:  3ffeead0 0883f900 3fff1478 40202d54  
3ffffed0:  3fff337c 3fff147c 3fff1478 4022670d  
3ffffee0:  00000000 0104a8c0 00000010 00000000  
3ffffef0:  00000000 00000010 3ffefe40 40221001  
3fffff00:  40210000 00000000 0000007d 3fff151c  
3fffff10:  3ffebae4 3fff1520 3fff3434 40224b39  
3fffff20:  3fff1370 3fff1fac 3fff1fac 4021547e  
3fffff30:  40215972 3ffed310 3ffebabc 3fff1fac  
3fffff40:  3ffebad6 00000000 3fff3434 40223f35  
3fffff50:  0204a8c0 3ffee318 02a93dee 00000000  
3fffff60:  40104b62 02a93dee 3ffeead0 60000600  
3fffff70:  4022d230 3ffeeaa8 3ffeead0 0884220c  
3fffff80:  4022d256 3fffdab0 00000000 3fff2004  
3fffff90:  3fffdc90 00000000 3fff3434 4022ce8b  
3fffffa0:  40000f49 3fffdab0 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v00000000
~ld

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started

Я попробовал обновить код, написав пользовательскую функцию «server.streamFile()» и добавив

"Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";

в заголовок, чтобы разрешить загрузку текстового файла как вложения.

Измененный код: [Изменена только функция handleDownload()]:

#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "<h1>Hello! from ESP8266!</h1>"
                "<p><a href=\"down\"><button>Download</button></a>";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    int32_t time = millis();
    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: "); Serial.println(fsizeDisk);

    String WebString = "";
    WebString += "HTTP/1.1 200 OK\r\n";
    WebString += "Content-Type: text/plain\r\n";
    WebString += "Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";
    WebString += "Content-Length: " + String(fsizeDisk) + "\r\n";
    WebString += "\r\n";
    server.sendContent(WebString);

    char buf[1024];
    int siz = dataFile.size();
    while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        dataFile.read((uint8_t *)buf, len);
        server.client().write((const char*)buf, len);
        siz -= len;
    }
    Serial.print(siz);
    Serial.println(" Bytes left!");

    dataFile.close();
    time = millis() - time;
    Serial.print(time); Serial.println(" ms elapsed");
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // don't do anything more:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}

Теперь, когда я нажимаю кнопку «Загрузить», в браузере открывается всплывающее окно с сообщением о начале загрузки файла «datalog.txt». Но примерно через 20–30 секунд появляется сообщение «Загрузка не удалась». ESP зависает после печати «fsizeDisk».

Тем временем на последовательном мониторе написано:

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600

Я не понимаю, что я делаю не так. Помогите, пожалуйста!

РЕДАКТИРОВАНИЕ: Я добавил delay(2) и Serial.println(cnt++) внутри while(siz > 0) в handleDownload() для отладки:

int cnt=1;
delay(10);
while(siz > 0) {
    delay(2);
    Serial.println(cnt++);
    size_t len = std::min((int)(sizeof(buf) - 1), siz);
    dataFile.read((uint8_t *)buf, len);
    server.client().write((const char*)buf, len);
    siz -= len;
}

Теперь происходит следующее: я получаю

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600
1
2
3
4
5
6
7
8

Цикл может зависнуть на любом счётчике (например, 10, 15, 17, 23 и т.д.). Кроме того, в моём браузере отображается, что загрузка выполнена на 28% (при cnt=8) или около того. Файл начинает загружаться, но зависает на середине. Я пробовал увеличивать задержку до 10 мс, но это не помогло.

, 👍0

Обсуждение

Попробуйте запустить Blink на вашем оборудовании на несколько минут, чтобы выявить проблемы с оборудованием/IDE., @Code Gorilla

В конечном счёте, вам, возможно, стоит обратиться к авторам порта ESP8266. Попробуйте скачать файл, никуда его не сохраняя (просто удалите данные), или сгенерировать фиктивные данные в файле и сохранить его. Также можно попробовать использовать небольшой тестовый файл с известным содержимым. И попробуйте другую SD-карту. Как вы её питаете? Карта может потреблять больше тока при записи., @Chris Stratton

Я уже задавал этот вопрос на [форуме esp8266](http://www.esp8266.com/viewtopic.php?f=160&t=12795&sid=38a2ce184063890c9f2f61a495e9a17b). Ответов пока нет. Я питаю NodeMCU через USB 2.0 от своего ноутбука. Не думаю, что SD-карта тут в этом виновата. Я ничего не записываю на карту, а только читаю с неё. Попробую использовать файл небольшого размера (~2 КБ). Также попробую скачать файл, никуда не сохраняя., @Ashish Ranjan


1 ответ


1

попробуйте добавить команду yield() в ваш цикл wihle. Благодаря yield() у ESP появляется время для выполнения фоновых задач.

,

Я попробовал добавить delay(2) в цикл while. Теперь загрузка начинается, но не завершается. Я пробовал задержку до 10 мс, но это не помогло. Попробую добавить yield(). А пока, пожалуйста, ознакомьтесь с ПРАВКОЙ., @Ashish Ranjan