Загрузка файла с 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 мс, но это не помогло.
@Ashish Ranjan, 👍0
Обсуждение1 ответ
попробуйте добавить команду yield() в ваш цикл wihle. Благодаря yield() у ESP появляется время для выполнения фоновых задач.
Я попробовал добавить delay(2) в цикл while. Теперь загрузка начинается, но не завершается. Я пробовал задержку до 10 мс, но это не помогло. Попробую добавить yield(). А пока, пожалуйста, ознакомьтесь с ПРАВКОЙ., @Ashish Ranjan
- Как разрешить междоменные запросы на ESP8266 WebServer
- Почему мы используем client.flush() в коде, когда мы подключаем Esp8266 к Интернету или серверу?
- Управление реле 5В с помощью Wemos D1 R1
- Проанализировать большой ответ json с помощью ESP8266
- ESP8266 отправляет веб-страницу клиенту, но html-коды отображаются в браузере вместо веб-страницы
- Загрузить сайт с SD-карты
- Проблема с nodemcu esp-01 не могу подключиться к wifi
- Создать один сервер в режиме точки доступа, а другой - в режиме станции.
Попробуйте запустить 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