ESP-8266/ESP32 NodeMCU Lua: азы программирования.

Тема в разделе "ESP8266, ESP32", создана пользователем ИгорьК, 25 июл 2017.

  1. Mitrandir

    Mitrandir Гуру

    Пока не могу придумать как на с++ подгружать и выгружать код на лету.
     
  2. DIYMan

    DIYMan Гуру

    1/2off: давно думаю над байткодом и его визуальным редактором, чтобы можно было делать процитированное. Оно не то, чтобы сильно прям нужно, но - иногда очень хочется :)

    Пока всё, что сделал: это сценарии в виде команд к контроллеру, хранимые на SD. По итогу контроллер в подписи можно превратить в полуавтоматический делатель чего угодно, практически. Удобная вещь, короче. Это я к тому, что изменение логики "на лету" - иногда действительно востребовано. Хотя и со многими оговорками, как по мне (т.е. не является самоцелью, как минимум).
     
  3. swc

    swc Нерд

    По ESP32. Перейти заманчиво. Вернее, не совсем, но для некоторых задач полезно. Однако, по моим сведениям 3-х месячной давности, в NodeMCU-32 еще не реализована библиотека UCG. (Нужна мне для графического интерфейса). Это сдерживает.
    Возможность выполнения скриптов "на лету" делает LUA незаменимым.
    Библиотеки JS, равно, как и Питона еще не совсем устоялись и по возможностям уступают NodeMCU.
    Поэтому говорить о переходе на эти языки еще рановато.
     
  4. Mitrandir

    Mitrandir Гуру

    Полноценный движок сценариев равносилен написанию свое прошивки с луа
     
  5. Mitrandir

    Mitrandir Гуру

    В моей задумке это критично, вставил флешку с прошивками, выбрал в меню и запустил.
     
  6. DIYMan

    DIYMan Гуру

    Ну я за полноценный и не говорил, у мну реализовано что-то вроде такого:

    1.png 2.jpg.png

    При этом внутри сами сценарии - это текстовые команды к контроллеру:

    3.png

    Всё расширяется/ужимается, в зависимости от модулей, включенных в прошивку. При этом визуально сценарий выглядит как кнопка на TFT-экране: жмакнули - сценарий запустился. Жмакнули ещё раз - сценарий остановился. Сделать на подобной основе полуавтоматический поливатор ста зон полива - раз плюнуть, и без перезакачки прошивки. Ввёл по требованию пользователей: надо, чтобы супруга имела возможность жмакнуть одну кнопочку, и полив пошёл бы последовательно, от зоны к зоне.

    Ну не доверяют люди автоматике, так и норовят - ручонками поклацать :)
     
    Mitrandir нравится это.
  7. Mitrandir

    Mitrandir Гуру

    Ну на таком супермарио не напишешь
     
  8. DIYMan

    DIYMan Гуру

    Дык и не стоит такой задачи :)
     
  9. Mitrandir

    Mitrandir Гуру

    В том то и дело, что стоит. у меня)
     
  10. DIYMan

    DIYMan Гуру

    Имхо, подход такой же, только байт-код генерить, и всё.
     
  11. Mitrandir

    Mitrandir Гуру

    хотя esp8622 стоят по 100 рублей,
    можно сделать кнопки/джостики/экран/ батарейки в корпусе геймбоя, а проц ( есп) в катридже
    захотел в другую игру, вытащил катридж с уже прошитым процом и вставил новый процессор
     
    DIYMan нравится это.
  12. DIYMan

    DIYMan Гуру

    Воот! Правильные мысли ;) Стоит ли оно того, если ESP стоит 100 рублей? ;)
     
  13. Mitrandir

    Mitrandir Гуру

    Вроде как в денди так и было сделано.
    в приставке только контроллеры джойстика ,бп и конвертер на телик, остальное в катриджде

    правда встанет еще вопрос как на экран nextion доставить его прошивку.
    Пока вижу так:
    на флешке лежат tft фаилы прошивки nextion экрана в которых залиты спрайты ( каждый фаил такой до 4 мб)
    а так же lua фаил со скриптом игры.
    основная прошивка считывает список игр на флешке и при выборе игры прошивает экран спрайтами и далее по юарту шлет ему комманды: нарисуй спрайт такой то по таким координатам. хотя может есть дешевая память метров на 10, но куда-то мы уже в оффтоп ушли)
     
    Последнее редактирование: 4 сен 2018
  14. ИгорьК

    ИгорьК Гуру

    32. Про while, tmr.now(), tmr.delay()
    Усомнившиеся по каким-то причинам в величии Аруино и начавшие изучать Lua повторяют одну и ту же ошибку.
    loop-мышление, то есть представление о программе как о закольцовке последовательных шагов приводит к появлению таких конструкций:

    upload_2018-9-7_11-19-25.png

    Или
    upload_2018-9-7_11-17-24.png

    Это примеры с нашего форума.

    Такие вещи в Lua нехороши по двум причинам.

    1. Ограничения системы.
    В NodeMCU не приветствуются глухие циклы, длительностью более 15 мс: "The SDK states that if any tasks run for more than 15 mSec, then services such as WiFi can fail."

    Ну а по поводу любимого правоверными ардуинщиками tmr.delay сказано вот что:
    "This is in general a bad idea, because nothing else gets to run, and the networking stack (and other things) can fall over as a result. The only time tmr.delay() may be appropriate to use is if dealing with a peripheral device which needs a (very) brief delay between commands, or similar. Use with caution!"

    То есть, оно и в ардуино то нехорошо, но если уже вы взялись за модуль с wif - применение таких фокусов приводит к абсолютно непрогнозируемым последствиям, поскольку система внутри себя ВСЕГДА имеет ряд неконтролируемых вами процессов, которые вы рушите долгими циклами и остановками.

    Кроме сказанного выше, неисключен укус бешеной собаки:
    "If tasks take longer than 500mSec then the watchdog timer will reset the processor. This watchdog can be reset at an application level using the tmr.wdclr() function, but this should be avoided."
    Вот пример краха системы из второго кода:
    [​IMG]


    2. Потеря логики.
    В Lua/JavaScript нет логического цикла программы. Программа всегда реагирует на события. Вы определяете для себя необходимое событие и пишете реакцию на него.

    Там где возникают слова "периодически", "до тех пор пока" - там должен быть таймер.
    (А там где есть таймер - там нет места tmr.delay()!)

    Как это решается? Исправим приведенные выше примеры.
    Код (Lua):
    -- Это неправильный код, хотя понятны намерения автора:
    wifi.sta.connect();
    print(wifi.sta.status());
    tmrstart = tmr.now();
    --- Кошмар:
    while (tmrstart + 1000*1000*2) > tmr.now() do  end
    print(wifi.sta.status());

    -- Исправляем.
    -- В коде надо напечатать статус wifi через 20 cекунд и если
    -- wifi есть - что-то сделать.
    -- Вот как правильно:

    wifi.sta.connect()
    print(wifi.sta.status())

    function donext()
        print(wifi.sta.status())
        --... делаем что-то дальше
    end
    -- Каждые две секунды проверяем статус wifi
    tmr.create():alarm(2000, 1, function(t)
        -- Соединение есть:
        if wifi.sta.status() == 5 then
            t:stop() -- Останавливаем этот таймер
            t:unregister() -- Отменяем регистарцию таймера
            t = nil -- Уничтожаем его
            donext() -- Выполняем необходимую функцию
        end
    end)
    Ну и другое пояснение:
    Код (Lua):
    -- Автор написал:
    while a<=128 do
        a= a+1
        print(a)
        tmr.delay(100000)
        str1= a
        init_OLED(sda,scl)
        print_OLED()
    end

    -- Нужно так:
    init_OLED(sda,scl)
    printall = function()
        a = a+1
        print(a)
        str1 = a
        print_OLED()
    end

    -- Вызов функции через 100 мс
    tmr.create():alarm(100, 1, function(t)
        if a > 128 then
            t:stop() -- Останавливаем этот таймер
            t:unregister() -- Отменяем регистарцию таймера
            t = nil -- Уничтожаем его
        else
            printall()-- Выполняем необходимую функцию
        end
    end)
     
    Последнее редактирование: 8 сен 2018
    Mitrandir нравится это.
  15. Mitrandir

    Mitrandir Гуру

    А как быть если нужна длительная математическая молотилка?
     
  16. ИгорьК

    ИгорьК Гуру

    Формально не готов ответить - нужно смотреть код. В целом: если есть безумный цикл - его надо превратить в функцию и звать не чаще чем через 5 мс.
     
    Mitrandir нравится это.
  17. Mitrandir

    Mitrandir Гуру

    Хотя вычислительные алгоритмы представляют огромное количество быстрых итераций и цикл можно повторяющимся таймером заменить.
     
    ИгорьК нравится это.
  18. ИгорьК

    ИгорьК Гуру

    Да вы просто с учетом сказанного выше сможете сами написать код.
    Если все таки требуется скорость - останавливайте wifi на время вычисления.
    Плюс учитывайте:
    "If tasks take longer than 500mSec then the watchdog timer will reset the processor. This watchdog can be reset at an application level using the tmr.wdclr() function, but this should be avoided."
     
  19. ИгорьК

    ИгорьК Гуру

    И про рекурсию не забыть. В случае с рекурсией все будет работать. Вместо таймера.
    Но помните, что для рекурсии функция должна объявляться заранее:

    Код (Lua):
    do
        local a = 0
        local frec
        frec = function()
            print(a)
            a = a + 1
            if a > 500 then return end
            frec()
        end
        frec()
    end
     
    Так должно работать с любым количеством итераций.
    Должно. Но как там на самом деле....

    Вот так:
    upload_2018-9-7_13-12-0.png

    А вот так - работает:
    Код (Lua):
    do
        local starttm = tmr.create()
        local a = 0
        local frec
        starttm:register(5,tmr.ALARM_SEMI,function()frec()end)
        frec = function()
            print(a)
            a = a + 1
            if a > 1000 then return end
            starttm:start()
        end
        starttm:start()
    end
    upload_2018-9-7_13-18-57.png
     
    Последнее редактирование: 7 сен 2018
  20. SergeiL

    SergeiL Гуру

    Но рекурсией нужно пользоваться аккуратно.
    При каждом вызове функции стек отедается, а освобождается только на выходе из функции.
    Может не хватить.;)