• Система автоматизации с открытым исходным кодом на базе 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:)
 
Сверху Снизу