• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Работа с uart в esp8266

hd44780

New member
Привет всем.

Есть у меня модуль ESP-03. На AT-командах в принципе всё работает, но декодировать текстовые ответы в контроллере - это нечто :)..
Плюс к этому - режим AP не нужен, подключение к разным хостам не нужно и пр..

Поэтому озаботился написанием своей, узкоспециализированной прошивки.
Начитался всякой всячины, поставил SDK - http://geektimes.ru/post/241842/ . Там есть куча примеров :).
Всё понял нормально, опыт работы программистом вообще и с разными МК в частности достаточный - 16 лет, если не больше.

Разработал свои команды (как я хочу их видеть), написал. Проверяю через FT232 и терминальную прогу. Эта связка проверенная и адееватная.

Моя прошивка в целом (по ряду косвенных признаков) ожила. Но есть достаточно серъёзная проблема с уартом.
Когда я пытаюсь слать в уарт побайтно - не фига не шлётся, либо шлётся какой-то бред.
После этого работы над прошивкой приостановил, начал целенаправленно разбираться с уартом.
Нашёл пример, который по таймеру раз в секунду гонит в уарт строку. Это работает нормально. Т.е. уарт вроде работает.
Начал копаться - выяснил следующее: в примере отсылается отсылают строка функциями
os_printf и
ets_uart_printf

. Эта функции из SDK, исходников для них нет.
Когда я попытался слать строку в цикле побайтно - вроде то же самое, но получаю я одни нули - 0x00. Столько нулей, какая длина строки.
Этого я пока до конца не осознал, ведь функции отправки байта в уарт я взял из исходной прошивки на AT командах.
Кто-нибудь знает, как правильно отсылать байты в UART?

Полный проект прилагаю. Спасибо.
 

Вложения

pvvx

Активный участник сообщества
Кто-нибудь знает, как правильно отсылать байты в UART?
Printf функции не стоит использовать в прерываниях по таймеру. Пишите прямо в регистры uart с контролем заполнения его fifo. Смотрите процедуры в C:\Espressif\examples\IoT_Demo\driver\uart.c
Или так:
Код:
/******************************************************************************
 * FunctionName : uart_tx_char
 * Description  : Use uart interface to transfer one char
 * Parameters   : uint8 TxChar - character to tx
 * Returns      : false, если не лезет в буфер fifo UART tx.
*******************************************************************************/
bool ICACHE_FLASH_ATTR uart_tx_char(uint8 *pch)
{
      uint32 fifo_cnt = READ_PERI_REG(UART_STATUS(UART0)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S);
      if (fifo_cnt >= (126 << UART_TXFIFO_CNT_S)) { // не влезет
         return false;
      }
      WRITE_PERI_REG(UART_FIFO(UART0) , *pch);
      return true;
}
Но есть масса условий, включен или нет вывод символов по прерыванию UART в ROM и подобное. Т.е. требуется инициализация UART со всеми процедурами.
По умолчанию, работает uart_tx_one_char(uint8 сhr); ets_putc(uint8 сhr); но они ожидают отправки символа (если fifo полное) и при использовании их всё будет тормозиться до срабатывания WDT. Т.е. для их использования следует отключить WDT при использовании низких скоростей передачи на UART.
 

sobs

New member
декодировать текстовые ответы в контроллере - это нечто :)..
Не так уж и сложно декодировать их контроллером, правда объем программы получается довольно солидным. Я как раз этим сейчас занимаюсь. За основу взял парсер отсюда http://chipenable.ru/index.php/programming-avr/item/192-prostoy-parser-dlya-mikrokontrollera.html.
 

sobs

New member
Использование АТ плохая идея
Если бы AT были только тут:( По работе сталкиваюсь с SIM900 - там нет возможности работать без AT. Поэтому и написал для себя, как мне кажется удобную, библиотеку. Вот скину свой проект, он пока черновой и без комментариев, но если будут вопросы - отвечу:) Эта библиотека позволяет абстрагироваться от AT команд)
Это простой WEB сервер. Клиент запрашивает страницу или картинку, контроллер ищет ее на карте памяти, если находит - отсылает, если нет, то посылает страницу 404. Есть возможность вывода и динамических страниц (так сделана главная страница /)
 

Вложения

Последнее редактирование:

pvvx

Активный участник сообщества
Если бы AT были только тут:( По работе сталкиваюсь с SIM900 - там нет возможности работать без AT.
? У SIM900 есть sdk http://microchip.ua/simcom/?link=/SIM900x
Не нашел динамических страниц. Везде указывается "Content-Length:" + Uint32ToStr(content_length + other_param);
"Динамическая" - это вроде генерируется на ходу и размер не известен заранее...
 
Последнее редактирование:

pvvx

Активный участник сообщества
Извиняюсь, не видел раньше его. Да и если честно не сильно искал:)
URI запроса может иметь полное имя:
GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
Или относительное:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org

Зависит от проксей и т.д.
Описание http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
Заголовок может быть разбит на куски - в зависимости от размера буферов роутеров и прочего попавшегося на пути передачи запроса вашему модулю, а так-же от соображений/воображений самого эксплорера :) ...
 

sobs

New member
Это я учту:)
Еще раз извиняюсь, не увидел вопроса про динамические страницы
Сама страница
Код:
<!DOCTYPE html>
<html>
   <head>
     <title>
       Главная
     </title>
     <meta http-equiv="REFRESH" content="30; URL=/">
   </head>
   <body style="background-color:#CCCC99;">
     <form action='/' method='GET'>
       Enter value (0..1000):
       <input type='text' name='pwm' size='4' value=''>
       <input type='submit' value='OK'><br />
     </form>
     <b>Значение value = </b><br />
     <b>Количество запросов = </b><br />
     <hr /><a href="bever.html">Бобер</a>
     <br /><a href="bever_gif.html">Слоник</a>
   </body>
</html>
Как видите <input type='text' name='pwm' size='4' value=''> значение value пустое, и тут
<b>Значение value = </b><br />
<b>Количество запросов = </b><br /> после = пусто.

Вот код обработки страницы
пока не дороботка есть в SD_Send_Content. Если страница больше 2Кб, она разбивается на блоки и если имя параметра находится в разрыве этих блоков, то этот параметр теряется..
Код:
if (PARS_EqualStr(http.URL, "/")){
             if (http.parameter_counter == 1){//проверяем был ли в запросе параметр
               value = PARS_StrToUint(http.parameter_value);//сохраняем значение параметра(раньше я его к ШИМу привязывал
             }
//заполняем структуру с динамическими параметрами
             Copy(parameter.parameter_name[0], "value='", Length("value='"), 0);
             Copy(parameter.parameter_value[0], Uint16ToStr(value), Length(Uint16ToStr(value)), 0);
             parameter.parameter_status[0] = 1;
             Copy(parameter.parameter_name[1], "Значение value = ", Length("Значение value = "), 0);
             Copy(parameter.parameter_value[1], Uint16ToStr(value), Length(Uint16ToStr(value)), 0);
             parameter.parameter_status[1] = 1;
             Copy(parameter.parameter_name[2], "Количество запросов = ", Length("Количество запросов = "), 0);
             Copy(parameter.parameter_value[2], Uint16ToStr(kol), Length(Uint16ToStr(kol)), 0);
             parameter.parameter_status[2] = 1;
//и выводим страницу.
             f_res = SD_Send_Content(http.ID, "0:index.html", HTTP_HEAD, &parameter);
             if (f_res == FR_OK) kol++;
           }
В SD_Send_Content идет поиск параметра и вставка в него значения.
Надеюсь понятно объяснил;)
 
Последнее редактирование:

hd44780

New member
pvvx, спасибо большое, Ваша функция передачи байта в тестовой прошивке работает нормально. В течении дня внесу в свою основную прошивку, отпишусь.
Про функции printf в прерываниях я знаю, не первый год этим занимаюсь. Но то был такой пример. Я его в чистом виде запустил, чтобы оценить работоспособность.
Прошивку sobs скачал, посмотрю, может пригодится.
Идея Web-сервера в модуле мне тоже интересна, но мне пока рано об этом думать, сперва надо основной функционал запустить.
Я почитываю тему http://esp8266.ru/forum/threads/razrabotka-biblioteki-malogo-webservera-na-esp8266.56/ , изучаю прошивку, которая там выложена, но сам к этому ещё не приступал.
 

pvvx

Активный участник сообщества
....
про динамические страницы
Там у вас ещё не указан отказ от кеширования для "динамических" страниц...
Не передавайте "Content-Length:" для динамических страниц. Смотрите в запросе HTTP/1.1 и если оно есть, то передавайте "шинковкой" ("Transfer-Encoding: chunked\r\n"), иначе по концу передачи давайте disconnect соединения. Броузеры того века пусть мучаются (они "соображают" по disconnect-у соединения, а у вас в ESP8266 остается структура в памяти на 60 сек и много соединений не обработаете - память кончиться :) ).
Если страница больше 2Кб, она разбивается на блоки и если имя параметра находится в разрыве этих блоков, то этот параметр теряется..
Это, с текущей AT прошивкой не решил пока никто и скорее всего не решит, без изменения исходников AT прошивки. Надо ловить disconnect соединения во время передачи и смену ID, а эксплореры лезут сразу с 5-ю соединениями на порт 80 (у AT максимум 4-ре, что ответит AT прошивка 5-ому соединению на каждую страницу браузеру? Пошлет? Он это дело и закэширует - типа нет там ничего :) ) ... ну и т.д. :)
Ещё попробуйте заслать запрос в 100500 байт на TCP порт в AT , для теста :) Костыли в прошивке SDK уже превышают все разумные пределы.
 
Последнее редактирование:
  • Like
Реакции: sobs

sobs

New member
Правильно ли я понял, что нужно указать Cache-Control: no-store ?
Не передавайте "Content-Length:" для динамических страниц
Это только для надежности? Просто длину страницы можно вычислить после всех преобразований.
И еще вопрос. При запросе страницы с несколькими картинками, браузер сначала запрашивает страницу, и потом сразу все картинки. Нельзя ли сделать так, чтобы браузер запросил первую картинку, подождал ответа, потом следующую и тд? Впринципе у меня и так работает, но иногда запрос на 2 картинки идет слитно (без паузы) и тогда у меня вторую картинку не выводит.
Извините за тупые вопросы, просто HTTP занялся 2 недели назад, пока все не осилил.
 

pvvx

Активный участник сообщества
Извините за тупые вопросы, просто HTTP занялся 2 недели назад, пока все не осилил.
Тут все такие - нельзя объять необъятное...(я тоже, не так давно решил узнать, как тама дела у современных HTTP и что нового наплодили за последние годы...)
И это не HTTP, а поведение конкретного эксплорера. В основных эксплорерах что-то появляется новое, остальным приходится тоже повторять со своими ошибками. Так возникают стандарты :)
Микрософт Эксплорер и Хром сразу открывают от 5-ти соединений, не смотря что там, если порт 80. Дальше, если что-то там завяжется и им указать что HTTP1.0 и менее всего, то возможно, они и "очухиваются". Но это не всегда - зачем им работать с допотопным сервером?
Прошивку Espressif делает для Iot к своему серверу и там нет Web-HTTP - там JSON от Дугласа Крокфорда, которого уже все замещают на другой стандарт, чтобы не указывать Дугласа Крокфорда и для обхода множественных ограничений... :)
 
Последнее редактирование:

sobs

New member
Я использую Мозилу, попробовал указать HTTP1.0, ничего не изменилось:)
Про JSON не слышал, почитаю.
Столкнулся с проблемой - при сбойной загрузке картинки на странице, при ее обновлении эта картинка не запрашивается, соответственно я ее не шлю. Но страница до конца не загружается, ждет ее. Эта проблема на Мозиле и Эксплорере, на других не проверял.
Сама страница
Код:
<!DOCTYPE html>
<html>
    <head>
        <title>
            STM32
        </title>
        <meta http-equiv="REFRESH" content="10; URL=/stm32.html">
    </head>
    <body style="background-color:#CCCC99;">
        <div align="center"><img src="1.jpg" alt="STM32"></div>
        <div align="center"><img src="1.gif" alt="STM32"></div>
        <hr /><a href="/">Главная</a><br />
    </body>
</html>
Заголовки
Код:
HTTP/1.1 200 OK
Content-Type: text/html; charset=windows-1251
Cache-Control: no-cache
Content-Length: 356
Далее идет запрос на 1.jpg, заголовки которые я с ней шлю
Код:
HTTP/1.1 200 OK
Content-Type: image/jpg
Cache-Control: no-cache
Connection: close
Content-Length: 17875
А запроса на 1.gif нету. Правда где-то через минуту Мозила посылает повторный запрос, уже со всеми вложениями..
Может я не правильно использую заголовки? Или каких-нибудь не хватает?
 
Последнее редактирование:

hd44780

New member
Отписываюсь, как и обещал.

Вставил функцию в свою прошивку, сделал эхо выдаваемых команд, всё работает. Пошёл делать дальше.
 

pvvx

Активный участник сообщества
Я использую Мозилу, попробовал указать HTTP1.0, ничего не изменилось:)
Измените номер порта и "обычно" кол-во запросов у эксплореров будет = 1.
Про JSON не слышал, почитаю.
JSON - это обобщенно. Не конкретно сам язык, в метод работы в HTTP с ним.
Столкнулся с проблемой - при сбойной загрузке картинки на странице, при ее обновлении эта картинка не запрашивается, соответственно я ее не шлю. Но страница до конца не загружается, ждет ее. Эта проблема на Мозиле и Эксплорере, на других не проверял.
....
А запроса на 1.gif нету. Правда где-то через минуту Мозила посылает повторный запрос, уже со всеми вложениями..
Может я не правильно использую заголовки? Или каких-нибудь не хватает?
Закодируйте в base64 свои картинки и вставьте в тело, чтобы было одно соединение. Картинки и страница у вас всё равно не более 2-х mss (1560*2 байта, tcp_mss(pcb)*2 ) и лезут за раз при передаче в стек LwIP-у при первой передаче:
uint16 len = tcp_sndbuf(pcb); // размер текущего окна стека
далее у LwIP-а есть экстра буфер на 1 mss и передача блоков, кратная mss самая быстрая и оптимальная.
по тому далее вычисляется кто меньше len = mMIN(tcp_mss(pcb) << 1, len); // len или (tcp_mss(pcb) << 1)
и производится передача данных в буфера pbuf LwIP: err = tcp_write(pcb, psent, len, 0); с командой вызова отсылки буферов err = tcp_output(pcb); // передать
В AT это всё нарушено - там нет оповещения максимального размера стека перед передачей, зависящего от обоих сторон (клиента и сервера) и т.д. А буфера там никто не держит... Если вы заполнили стек клиенту, и он указал уменьшение "окна" в нуль, то передать временно, пока он не объявит о увеличении "окна" и пройдут все подтверждения ACK TCP ничего не выйдет. Как это решается в AT? - никак, просто багами и скипанием всего :) Т.е. ситуация с AT хуже чем с UDP - гарантий о доставке и т.д. никаких.
Но AT пойдет для "детской игрушки в тепличных условиях", если передавать до 10 байт - вкл/выкл лампочку и для этого "парсеры" не требуются. На большее она не рассчитана.
 
Последнее редактирование:
  • Like
Реакции: sobs

sobs

New member
Измените номер порта
Вот этого не пробовал. Завтра обязательно попробую и отпишу.
Вторую часть сообщения не понял:). У меня устройство проработало сутки без сбоев, правда там была одна "динамическая" страница, и три статические страницы с одной картинкой (jpg, gif, png). Они каждые 10 секунд после полной загрузки переключались. Пробовал разные разрешения, вплоть до jpg 1,6mb. Все стабильно. Но если делаю несколько картинок на 1 странице, то примерно каждые 5 обновлений приходилось вручную переобновлять страницу. Максимальную скорость "выжал" 130кбит/сек.
PS. Прошивка AT v0.20. Пробовал 0.21 - каждые пару минут теряет соединение, и сильно греется микросхема.

PPS. По поводу вставки изображения в саму страницу - тоже вариант, но буду использовать если больше ничего не добьюсь:)
 
Последнее редактирование:

pvvx

Активный участник сообщества
У меня устройство проработало сутки без сбоев, правда там была одна "динамическая" страница, и три статические страницы с одной картинкой (jpg, gif, png). Они каждые 10 секунд после полной загрузки переключались. Пробовал разные разрешения, вплоть до jpg 1,6mb. Все стабильно. Но если делаю несколько картинок на 1 странице, то примерно каждые 5 обновлений приходилось вручную переобновлять страницу.
Это и есть "в тепличных домашних условиях", когда все запросы и условия нормированы. В реальном инет всё по другому...

http://validator.w3.org/ говорит на мой тестовый web:
Errors found while checking this document as HTML 4.01 Transitional!
Result: 42 Errors, 37 warning(s)
Address:
Modified: (undefined)
Server: PVs/0.1
Size: (undefined)
Content-Type: text/html
Encoding: windows-1251 (detect automatically)
Doctype: HTML 4.01 Transitional (detect automatically)
Root Element: html


http://www.webpagetest.org/ :
webpagetest.gif
И т.д. (ссылок на online проверяльщиков в инет море)
 
Последнее редактирование:

pvvx

Активный участник сообщества
PS. Прошивка AT v0.20.
AT 20 и всё старее SDK 0.9.5 вообще не катируется. Там, при закрытии соединения со внешней стороны, происходит потеря соединения и вечное зависание внутренней процедуры на таймере, пытающейся закрыть "пустую память", где когда-то сидела структура соединения. Через 4-ре таких происшествия, больше TCP соединений не открыть. Так-же там данные отправляются в чужое (другое) соединение, если прошлое закрылось внешним сервером/клиентом и открылось новое :) Плюс полная беда с ID соединений из-за описанных внутренних ошибок. В SDK 0.9.5 это частично переписано, но есть другие ошибки и часть прошлых.... Всё, что базируется на функциях espconn в прошивке = баг. К этому относятся все проекты (Прошивки, основанные на AT командах , NodeMCU, NodeLua, MQTT, MicroPython, ... ), кроме использующих внутренний стек LwIP напрямую. От такого позора Espressif и закрыл все исходные коды, т.к. они теперь представляют из себя один большой патч их неверно выбранных алгоритмов работы со стеком LwIP.
 
Последнее редактирование:

sobs

New member
Попробовал поменять порт - браузер все равно кучу соединений делает, в общем ничего не поменялось:(
Попробовал вставить картинки как base64 - все замечательно. Сделал страницу с 3мя картинками объемом 2,6 мегабайт - все грузится без сбоев:)
AT 20 и всё старее SDK 0.9.5 вообще не катируется
Насколько я понял, к этому SDK Espressif выпустили патч, но AT 21 не обновили. По крайней мере у меня она теряла соединение просто так. AT 20 в этом плане по стабильней.
Сам жду когда избавятся от их SDK:)
 
Сверху Снизу