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

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

  1. ИгорьК

    ИгорьК Гуру

    Водная часть.

    Информация. Никакими ошибочными прошивками модуль ESP-8266 убить нельзя. Переводите его в режим прошивки и шьете в сотый раз ( lua, micropython, arduino, AT, espruino, etc) до получения эффекта. Смелее!

    Кстати: паяльник.

    Зачем это нужно - тратить время и напрягать мозги?

    (1) Событийный и (2) асинхронный код (ардуинщик! ты в принципе то знаешь что это?) - чтобы писать его на Си, надо очень много тренироваться. Следствие - объем материала переработки в мозге для Lua в десятки(!) раз меньше, чем для Си.

    Ты - кто?
    Самодельщик? Lua - это твое, ибо твоя задача делать устройства, а не копаться в регистрах МК.

    Любитель программировать? Конечно Си, Си++ (язык Ардуино). Глубина его сравнима с глубиной Марианской впадины.

    (На глубине, из-за высокого давления, вероятны проблемы с головой: снобизм, высокомерие, холивар, "обучение жизни" - суть времяпровождения некоторых перегруженных знаниями регистров МК.)

    Lua, JavaScript, Python множат на ноль время, проведённое за механическим чтением значений того или иного регистра и высвобождают его для доброго DIY.

    Поняв Lua, вы сможете кодить на JavaScript семейство Espruino, в том числе Iskra JS - платы на порядок мощнее чем обычная Ардуино.

    Итак:
    • событийное программирование - нет никаких закольцовок кода (отсутствует loop). Добавление новых событий есть просто дописывание новых кусков. Добавив в устройство новый элемент вы не будете думать как и куда его "воткнуть" в код (обычная проблема ардуинщиков: у меня есть скетч А и сектч Б, не могу их соединить).
    upload_2018-10-10_9-38-48.png

    • (особенность ESP8266) Вы можете держать в глобальных переменных необходимые значения, а программа состоять из чреды запускаемых на исполнение скриптов, записанных во флэше (как реакции на разные события).

    Во флэше памяти столько, сколько сами напаяете, поэтому даже при ограниченной "оперативной" памяти (в которую много не затолкаешь) программа может быть очень и очень большой.

    Весь скрипт не надо держать постоянно в памяти: произошло событие - кусок загрузился, отработал, и выгрузился.
    • асинхронный код - реакции на разные события трудятся сами по себе, нет необходимости думать как их согласовать между собой;
    • скриптовый язык - изменение и наблюдение переменных во время работы программы в терминале;
    • Возможность видеть глобальные переменные одним кликом;
    • Подгрузка запуск и выгрузка скриптов.

    Полагаю, достаточно для объяснения преимуществ Lua перед Си для ардуинщика/самодельщика. Есть еще несколько, но начинающему они понятны не будут.

    ==================================================================

    Шаг первый - загружаем в модуль Lua прошивку:

    Был сайт, да сплыл... Прилагаемый файл lessonsLua.zip содержит PDF-копии страниц погибшего сайта.

    Или мое творчество здесь: http://forum.amperka.ru/threads/esp-8266-esp32-lua-азы-программирования-nodemcu.12558/page-29#post-203319

    ======================================

    Пару слов о в ESPLorer.


    ESPLorer имеет кнопок и менюшек очень много. Со временем они станут поняты. Но сейчас нам нужны главные операции, что нарисованы ниже. (По сути, все остальное "удобняшки")

    Левое окно - редактор скрипта: загрузить файл, изменить, сохранить на диск файл. Этот файл, также, можно сохранить и запустить на модуле, или запустить на модуле без сохранения на нем.

    Правое окно - терминал. В нем отражается информация, что гуляет между модулем и компьютером. Справа есть несколько полезных элементов управления.

    Для тех, кто боится ESPlorer - главные его кнопки:

    upload_2018-4-16_13-25-57.png

    upload_2018-4-16_13-13-39.png


    А так выглядит сообщение об ошибках:
    upload_2018-4-28_15-49-7.png


    Дальше - Шаг второй.

    ПС. (Многие скрипты примеров для этой ветки форума здесь)


    ======== Оглавление темы=========
    1. Шаг первый - здесь. Заряжаем ESP-8266, азы ESPlorer
    1.1. Заводим модуль в сеть.
    2. Шаг второй - Немного почитать.
    3. Шаг третий - Blink от Lua.
    4. Шаг четвертый - асинхронный код - много разных Blink.
    5. Шаг пятый - глубже: создание функций.
    6. Шаг шестой - первый модуль.
    7. Проверка памяти.
    8. Работа с памятью и модулями.
    9. Callback + DS18b20.
    10. MQTT - что это.
    11. Счетчик расхода воды. Пошагово.
    12. Маленький сервер.
    13. Про расписания.
    14. Установка значения по недельному расписанию.
    15. Допрос Народного Мониторинга.
    16. Модуль: забираем данные с Народного Мониторинга.
    17. Азы: изучаем память.
    18. Грузим файлы по wifi.
    19. DS2438 - батарейное питание и датчик температуры. Модель общения с любым 1Wire устройством.
    20. Анонимная функция и callback. Таймеры. (Для начинающих)
    21. Метатаблицы для чайников. Сылка на habrahabr. (Не для чайников, но очень полезно.)
    22. Таблицы для начинающих. Работа со штатным модулем DS18b20. (Для начинающих)
    23. init, wifi, mqtt. Скелет программы IoT. Ч.1. (Для начинающих)
    24. analize, pubnow, savedata. Скелет программы IoT. Ч.2. (Для начинающих)
    25. Скелет программы IoT ч.3.1. Освещение на улице. (Для начинающих)
    ===================================
     

    Вложения:

    • lessonsLUA.zip
      Размер файла:
      1,5 МБ
      Просмотров:
      4.241
    Последнее редактирование: 9 сен 2020
    Di_Mok, Un_ka, tpolimer и 9 другим нравится это.
  2. ИгорьК

    ИгорьК Гуру

    Ссылка на очень хорошее руководство на русском языке. Однако, помним, что версия Lua у нас 5.1, в руководстве - более поздняя 5.3.

    26. Скелет программы IoT ч.3.2. Плюс управляем отоплением по расписанию/вручную. (Для начинающих)
    27. Скелет программы IoT ч.3.3. Плюс охрана и сирена. (Для начинающих)
    28. Скелет программы IoT ч.3.4. Плюс полив огорода. (Для начинающих)
    29. Итог IoT: оно управляет отоплением, светом, поливом и охраняет одновременно.

    30. Часы на MAX7219.
    31. Модуль для MAX31855
    32. Про while/for, tmr.now(), tmr.delay(). (Начинающим, и всем ардуинщикам, читать в первую очередь!)
    33. Фича MQTT.
    34. Немного про ds18b20.
    35. Редактируем код на устройстве через сеть.
    36. Еще раз - отправка таблицы на брокер. Очень маленький файл.
    37. LFS от @swc - отличная работа!
    38. О памяти еще раз.
    39. Еще раз LFS - на компьютере от vklimk
    40. Сборка прошивки от vklimk.
    41. Модуль mh-Z19b - СО2 в воздухе.
    42. ESP32 - первые шаги.
    43. BH1750.
    44. Переписываем линейный код Ардуино. Избавление от delay().
    45. Текущие заметки ESP32 Lua. Прошивки ESP32.
    46. Fram FM24CL64B.
    47. Modbus PZEM-016.
    48. Связь с брокером с уничтожением потерянного соединения.
    49. ESP32 - Ajax Systems.
    50. i2c address.
    51. ESP32 вяжем с MQTT.
    52. Вновь об LFS от ioex
    53. Visual Studio & Lua от serg3295
    54. Тайна потери соединения с MQTT брокером.
    55. Данные действительны определенное время.
    Просто: http://tylerneylon.com/a/learn-lua/
    MTRF64+ESP32
    Метатаблицы и классы.

    MQTT
    DHT11

    О версиях NodeMCU.

    ==============================================================================

    Шаг второй.

    Находим книгу Роберту Иерусалимски "Программирование на языке Lua". Всего 381 страница.

    Если исключить описание нескольких стандартных библиотек - то страниц 220. Их все пока читать не обязательно: объектно-ориентированное программирование, например, для ESP-8266 встречается не часто.

    Остается 193 страницы. Справитесь? Нет? Да тоже не важно: любой язык состоит из двух вещей: управляющих конструкций и всего остального.

    Вот про управляющие конструкции и функции узнать следует - а об остальном поговорим позже.

    Для прочтения - только(!!!) 96 страниц
    .
    Там еще введение, оглавление и другая лабуда, которая будет все равно пропущена.

    Теперь внимание: все написанное здесь представляет собой иллюстрации к книге, а не ее замену, и, тем более, не учебник.

    Второе чтение, и его придётся делать постоянно (ставим в закладки) находится здесь: http://nodemcu.readthedocs.io/en/master/
    90% кода, который показывают вам (и выдают за свой), берется там. Читайте первоисточник, а не его перевранные копии.

    Еще почитайте: https://zserge.wordpress.com/2012/02/23/lua-за-60-минут/

    https://habr.com/post/184538/

    И улыбнемся преимуществам динамической типизации от Иерусалимски:

    upload_2019-7-16_14-2-31.png

    Интервью Иерусалимски: https://habr.com/ru/company/mailru/blog/459464/




    Шаг третий.
     
    Последнее редактирование: 25 июл 2022
    Un_ka, tpolimer, Юра 80 и 4 другим нравится это.
  3. ИгорьК

    ИгорьК Гуру

    Шаг третий.

    Внимание, важно(!!!):

    upload_2019-6-13_10-24-43.png

    После прочтения немногих страниц уже можно открыть какую-нибудь дурацкую тему где много буков про Lua и... ничего не понять.
    Все дело в том, что Lua в исполнении NodeMCU - это не совсем Lua, а JavaScript (Node.js) в нотации Lua, симбиоз:
    • событийно-ориентированный и
    • асинхронный код.
    Сначала это выносит мозг, потому что... Давайте составим простую программу.

    Например, наступит вечер - пойдем гулять. Пойдет дождь - возьмем зонт.

    Как это будет выглядеть на языке Ардуино?

    Код (C++):
    #define ЗОНТ офигенный
    #define ДОЖДЬ вода

    void раскрыли_зонт();

    setup {
        int дождливо = 55;
        unsigned long вечер = 12345678;
    }

    loop {
        if( millis() > вечер) {
            идем гулять;
            if(analogRead(ПинДождя) > дождливо) {
                раскрыли_зонт();
            }
        }
    }

    void раскрыли_зонт() {
        //....
    }
    Определили что надо и loop-имся - проверяем условия в цикле.

    Важно! На Lua loop не обнаруживается никогда. Так как же написать/понять программу без loop?

    А мы ее уже написали: наступит (событие) вечер - идем гулять, наступит (событие) дождь - раскроем зонт.

    Все. Именно такова логика событийного и асинхронного кода:
    • определяется событие и готовится реакция на него, после чего ожидается/разрешается событие;
    • вы не думаете (вообще не думаете) о том как согласовать происходящее между собой - асинхронный код сам организует.
    Теперь можно заново взглянуть на любой код на Lua NodeMCU - он станет гораздо понятнее. Не совсем, конечно, но событийные цепочки можно будет обнаруживать.

    Еще придется получить порцию неприятностей, которая обобщенно называется callback - его много в Lua. Да что много - построен на нем.

    Если ожидается событие, то мы как-то должны с ним связать необходимую реакцию.

    Функцию реакции написать несложно, типа - зажжем лампочку. Но как это воткнуть наступающему закату?

    Смотрим - заготовленные системой реакции на типовые события:

    callback.png

    Как этим пользоваться? Начнем блинкать лампочками - разберемся.

    Старт - здесь. Начали!
    Рассматриваем таблицу что рассказывает про ноги модуля:
    пины.png

    Слева что писать в коде, справа - то что рисуют на картинках в сопроводительной к модулю документации.

    Сделаем такой код:
    Код (Lua):
    do
    pin=1 -- Нога для блинка
    gpio.mode(pin, gpio.OUTPUT) -- Пин будет выходом
    ligth = 1 -- Это будем писать в выход

    function blink()
        -- все просто - пишем в выход
        gpio.write(pin, ligth)
        -- чтобы не плодить светодиодов
        -- дублируем в консоль что получается
        print("Write  to pin "..ligth)
        -- Это то же самое, что тренарный оператор в Сях
        ligth = (ligth == 0) and 1 or 0 -- Если выражение в скобках верно,
        -- то "ligth" присваивается 1, не верно - присваивается 0.
    end
    -- вызываем функцию
    blink()
    end
    Пишем код в левом окне Esplorer, весь выделяем, жмем кнопку "Block":
    блинк.png
    После этого ставим курсор на строку blink() и тапаем по кнопке "Line":

    блинк2.png

    Ура! Блинкует!
    ... но вручную. А где событиность и асинхронность? Начнем добавлять. Сначала событие.

    Событие у нас не ахти какое, но все таки - срабатывание таймера. Изготовим оный.
    Таймер - первый в таблице (см. выше) callback(ов), документация по нему здесь.

    Пишем код:
    Код (Lua):
    do
    pin=1 -- Нога для блинка
    gpio.mode(pin, gpio.OUTPUT) -- Пин будет выходом
    ligth = 1 -- Это будем писать в выход

    function blink()
        -- все просто - пишем в выход
        gpio.write(pin, ligth)
        -- чтобы не плодить светодиодов
        -- дублируем в консоль что получается
        print("Writе  to pin "..ligth)
        -- Этото же самое, что тренарный оператор в Сях
        ligth = (ligth == 0) and 1 or 0
    end
    -- вызываем функцию
    blink()

    --------------------   Добавляем  --------------------
    ------------------------------------------------------
    -- Создаем таймер
    tmrBlink = tmr.create()
    -- Интервал подмигивания
    interval = 5000
    -- как работает таймер, смотрим документацию:
    mode = tmr.ALARM_AUTO
    -- запускаем таймер
    tmrBlink:alarm(interval, mode, blink)
    end
    Выделяем весь код, жмем кнопку "Block" и наблюдаем:
    блинк3.png
    блинк4.png

    Все это можно было записать и по-другому, например не плодить переменные для таймера:
    Код (Text):
    tmrBlink = tmr.create()
    tmrBlink:alarm(5000, tmr.ALARM_AUTO, blink)
    Или еще проще - переменная со ссылкой на таймер нам не нужна - он бухает без надежды на остановку, поэтому:

    upload_2018-1-19_14-20-39.png

    Код (Text):
    tmr.create():alarm(5000, tmr.ALARM_AUTO, blink)
    Итак, наш первый блин(к, комом) создан и мы обошлись без loop.
    Кроме того, в режиме реального времени мы правили код и видели его результат без всякой компиляции - это преимущество любого скриптового языка, в Lua все сделано чрезвычайно удобно.

    Мы узнали что такое callback функция. Это функция, которая передается другой функции для исполнения.
    Передача осуществляется ссылкой, то есть просто названием функции.

    Обычно это имеет смысл тогда, когда в асинхронном коде нужно организовать цепочку событий: сначала происходит одно, и по результатам его нужно сделать что-то.

    В нашем простом случае с таймером это не слишком очевидно, но если вместо таймера - запрос к веб-странице, тогда все становится на место: сначала получили данные (никто не знает сколько времени на это потребуется), а потом их обработали функцией.

    Мы готовы к следующему шагу - будем делать несколько блинков с разным временем и поймем что есть асинхронность в деле.

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

    Код (Lua):
    do
    pin=1
    gpio.mode(pin, gpio.OUTPUT)
    ligth = 1
    tmr.create():alarm(5000, tmr.ALARM_AUTO, function()
        gpio.write(pin, ligth)
        print("Writе  to pin "..ligth)
        ligth = (ligth == 0) and 1 or 0
    end)
    end
    А чтобы закрепить материал о таймере, прогуляйтесь сюда.
     
    Последнее редактирование: 9 сен 2020
    Un_ka, Arthur Melkumov, tpolimer и 9 другим нравится это.
  4. ИгорьК

    ИгорьК Гуру

    Шаг четвертый.
    Пора мигать несколькими лампочками.
    Вот здесь то и начинается асинхронность, а мы работаем копипастой и не напрягаем голову:
    Код (Lua):
    do
    pin1=1
    pin2=2
    gpio.mode(pin1, gpio.OUTPUT)
    gpio.mode(pin2, gpio.OUTPUT)
    ligth1 = 1
    ligth2 = 1

    tmr.create():alarm(5000, tmr.ALARM_AUTO, function()
        gpio.write(pin1, ligth1)
        print("Writе  to pin1 "..ligth1)
        ligth1 = (ligth1 == 0) and 1 or 0
    end)

    tmr.create():alarm(3000, tmr.ALARM_AUTO, function()
        gpio.write(pin2, ligth2)
        print("Writе  to pin2 "..ligth2)
        ligth2 = (ligth2 == 0) and 1 or 0
    end)
    end
    Все понятно, одна лампочка мигает через пять секунд, другая - через три:
    блинк5.png

    Хотя пример и неказист, от показывает очень очень очень важный момент:
    код, подвешенный на таймер становится асинхронным.
    Мы просто создали два события - два таймера, и каждый из них запускает свой код независимо друг от друга.
    Это ценное наблюдение и его надо запомнить.
    =========================================

    Продолжим изучение основ.

    Все отлично работает, но копипаста - не наш способ.
    Вот что здесь происходит? Много похожих буков. А если надо еще лампочек добавить?

    В Луа есть интересная вещь: функция может не только получать функцию для исполнения, но и сама создавать и возвращать функцию, которую будет исполнять кто-то другой.

    Три кода далее выполняют АБСОЛЮТНО одну и ту же задачу, но я последовательно вносил в них изменения. Это сделано для того, чтобы вы их увидели и поразмышляли над происходящим.

    Напишем и выполним код A:
    Код (Lua):
    do
    function makeblink(pin)
        gpio.mode(pin, gpio.OUTPUT)
        local ligth = 1
        return function()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
    end

    blink1 = makeblink(1)
    blink2 = makeblink(2)

    tmr.create():alarm(1000, tmr.ALARM_AUTO, blink1)
    tmr.create():alarm(3000, tmr.ALARM_AUTO, blink2)
    end
    А потом код В:
    Код (Lua):
    do
    pin1 = 1
    int1 = 1000

    pin2 = 2
    int2 = 3000

    function makeblink(pin)
        gpio.mode(pin, gpio.OUTPUT)
        local ligth = 1
        return function()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
    end

    function maketimer(interval, call)
        tmr.create():alarm(interval, tmr.ALARM_AUTO, call)
    end

    maketimer(int1, makeblink(pin1))
    maketimer(int2, makeblink(pin2))
    end
     
    И в заключение код С:
    Код (Lua):
    do
    pin1 = 1
    int1 = 1000

    pin2 = 2
    int2 = 3000

    function makeblinkandtimer(pin, interval)
        gpio.mode(pin, gpio.OUTPUT)
        local ligth = 1
        function blink()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
        function maketimer()
            tmr.create():alarm(interval, tmr.ALARM_AUTO, blink)
        end
        return maketimer()
    end

    makeblinkandtimer(pin1, int1)
    makeblinkandtimer(pin2, int2)
    end
    Внимательно посмотрите как и что изменяется от скрипта к скрипту, и начнем разбираться с содеянным...

    Код (Lua):
    -- Фрагмент Кода А

    function makeblink(pin)
        -- получаем номер пина и устанавливаем выход
        gpio.mode(pin, gpio.OUTPUT)
        -- local - переменная ниже будет видна только в пределах
        -- данной функции
        -- однако она а) будет сохранена и б) дудет видна
        -- для той функции, которая ее вызывает
        local ligth = 1
        -- возвращается целая функция
        -- и эта функция будет видеть переменную "light"
        -- всегда.
        -- Это явление называется замыканием
        -- или "upvalue"
        return function()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
    end

    -- переменная blink1 теперь ссылается на
    -- функцию, которая оперирует миганием
    -- первой ноги
    blink1 = makeblink(1)

    -- дальше мы уже разбирали
    Код (Lua):
    -- Фрагмент Кода В

    -- Эта функция принимает на вход время и указатель на сallback функцию
    function maketimer(interval, call)
        -- Создает таймер, заряжает его временем и callback и запускает
        tmr.create():alarm(interval, tmr.ALARM_AUTO, call)
    end
    С Кодом С разбираетесь сами - принцип везде один. Код внутри функции makeblinkandtimer создает функцию blink, создает таймер, скармливает ему blink и таймер начинает отсчет.

    Разобрались? Пора сделать следующий шаг.
     
    Последнее редактирование: 19 янв 2018
    naz, Arthur Melkumov, Mitrandir и 6 другим нравится это.
  5. ИгорьК

    ИгорьК Гуру

    Шаг пятый. Азы таблиц.
    Код (Lua):
    pin1 = 1
    int1 = 1000

    pin2 = 2
    int2 = 3000
    ---
    makeblinkandtimer(pin1, int1)
    makeblinkandtimer(pin2, int2)
    Эта часть Кода С (из предыдущего поста) выглядит напряжно. Попробуем исправить ситуацию.

    Создадим таблицу.
    В эту таблицу будем вносить, в свою очередь, другие таблицы.

    Они будут содержать пары: номер пина и интервал для блинка.

    Скормим общую таблицу таблиц функции, которая будет перебирать строки и создавать блинки.
    Все что нам нужно будет - вставлять в таблицу пины и время, и получать любое число мигающих ног:

    Код (Lua):
    do
    -- таблица, а в ней...
    pinsintervals = {
        -- еще две (можно любое количество) таблицы
        -- номер ноги и период мигания
        {1, 1000},
        {2, 3000}
    }

    function makeblinkandtimer(pin, interval)
        gpio.mode(pin, gpio.OUTPUT)
        local ligth = 1
        function blink()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
        function maketimer()
            tmr.create():alarm(interval, tmr.ALARM_AUTO, blink)
        end
        return maketimer()
    end

    for _, v in pairs(pinsintervals) do
        makeblinkandtimer(v[1], v[2])
    end
    end
    Вы увидели значок "_" - подчеркивания. В Луа так пишут, когда функция обязательно возвращает значение, но оно нам для жизни не нужно - интерпретатор не резервирует переменную для возвращаемого значения, но учитывает его наличие.

    in pairs() возвращает два значения и первое нам не нужно.

    Полагаю, увидев этот код ранее, вы бы не смогли понять его логику, теперь, надеюсь, Луа покажется вам не таким страшным.

    Что можно сделать с нашей задачей еще?
    Следующий шаг...
     
    Последнее редактирование: 24 мар 2019
    ДедВова, SmileOfFortune, Ujine и 2 другим нравится это.
  6. ИгорьК

    ИгорьК Гуру

    Шаг шестой.
    Упакуем все в модуль и положим на полку - мало ли когда придется блинкать.
    Да-да, создадим библиотеку.

    Вот код с названием blinkmod.lua
    Код (Lua):
    do
    local M = {}
    M.pinsintervals = {}

    function M.makeblinkandtimer(pin, interval)
        gpio.mode(pin, gpio.OUTPUT)
        local ligth = 1
        local function blink()
            gpio.write(pin, ligth)
            print("Writе  to "..pin.." "..ligth)
            ligth = (ligth == 0) and 1 or 0
        end
        local function maketimer()
            tmr.create():alarm(interval, tmr.ALARM_AUTO, blink)
        end
        return maketimer()
    end

    function M.make(t)
        M.pinsintervals = t
        for _, v in pairs(M.pinsintervals) do
            M.makeblinkandtimer(v[1], v[2])
        end
    end
    return M
    end
    Сохраним его в памяти модуля.
    Код создает таблицу М и в ее поля записывает несколько объектов.
    M.pinsintervals - пустая таблица для приема таблицы с ногами и временем (На самом деле это не совсем точно, но при желании разберетесь в чем тут подвох.).
    M.makeblinkandtimer - функция уже нам знакомая.
    M.make - принимает таблицу ноги/время и формирует на нее ссылку в поле M.pinsintervals, после чего начиняет таймеры ногами и временем.

    Работаем с модулем так:
    Код (Lua):
    do
    pinsintervals = {
        {1, 1000},
        {2, 3000}
    }
    bl = require('blinkmod')
    bl.make(pinsintervals)
    end
    блинк7.png
    блинк8.png

    Друзья, если вы дотянули до этого места, уверен, вы уже можете сами понимать логику и писать программы на Lua.

    Остаются из важного coroutine и метатаблицы, но на начальном этапе для МК они не обязательны.

    Продолжение.
     
    Последнее редактирование: 25 мар 2018
    ДедВова, SmileOfFortune, Ujine и 2 другим нравится это.
  7. rkit

    rkit Гуру

    Ну потроллюсь, пожалуй
    Асинхронность. С лупами. Без уродливой каши из продолжений.
    Код (C++):
    #include <Arduino_FreeRTOS.h>
    void loop() {}

    struct BlinkerParams {
      uint16_t durationHigh;
      uint16_t durationLow;
      uint8_t pin;
    };

    void blinker(void *pvParameters) {
      auto params = *(BlinkerParams*)pvParameters;
      pinMode(params.pin, OUTPUT);
      while (1) {
        digitalWrite(params.pin, HIGH);
        vTaskDelay(params.durationHigh / portTICK_PERIOD_MS);
        digitalWrite(params.pin, LOW);
        vTaskDelay(params.durationLow / portTICK_PERIOD_MS);
      }
    }

    void setup() {
      xTaskCreate(blinker, "blinker1", 64, new BlinkerParams{100, 200, 13}, 8, NULL);
      xTaskCreate(blinker, "blinker2", 64, new BlinkerParams{1000, 500, 12}, 8, NULL);
    }
     
     
    Un_ka, Mitrandir, swc и 3 другим нравится это.
  8. ИгорьК

    ИгорьК Гуру

    Спасибо, rkit, за помощь! Ты настоящий Друг! Более крутого троллинга Сей трудно представить!
     
    Последнее редактирование: 27 июл 2017
    ДедВова нравится это.
  9. rkit

    rkit Гуру

    Не понял, каким образом это троллит си.
    Заменить auto на BlinkerParams, и будет чистый 100% работоспособный си.
     
    ИгорьК нравится это.
  10. ИгорьК

    ИгорьК Гуру

    rkit, не теряйте чувства юмора!
    95% читателей не поняли что Вы написали - это и есть чистый троллинг :)

    Ну и напомню, что с использованием библиотеки (не так ли?) мой код выглядит всего лишь как:
    Код (Lua):
    do
    pinsintervals = {
        {1, 1000},
        {2, 3000}
    }
    bl = require('blinkmod')
    bl.make(pinsintervals)
    end
     
    Ujine нравится это.
  11. SergeiL

    SergeiL Оракул Модератор

    Ну, какова цена, такова и расплата! :)

    Количество строк исходника, порой не показатель оптимальности ПО.
    Вопрос, в какое количество инструкций процессора они преобразуются, и за какое время выполняются.
    Опять же: латентность, джиттер...

    Учитываем компилятор / интерпретатор, приоритетность в асинхронных процессах.

    Задачи-то бывают разные.

    Я понимаю, что помигать светодиодом – задача тривиальная.

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

    Почему такая категоричность-то ???

    Точка с запятой утомляет? Еще недавно Вы сами комментарии из программы на LUA удаляли, чтобы места в памяти хватило.

    А объявление переменных позволяет выявить ошибки в названиях переменных, еще на этапе компиляции, а не мучиться с отладкой, используя в программе две совершенно разные переменные, отличающиеся ошибкой, в одой букве.


    Вы прекрасно объясняете прелести LUA, но каждый, наверное, сам должен определиться, что ему больше подходит.
     
    Ujine нравится это.
  12. ИгорьК

    ИгорьК Гуру

    Неужели Вы серьезно все это восприняли? :)

    Еще недавно, когда ардуинисты просто боялись подойти к этой плате, NodeMCU бесстрашно косячил с прошивкой. Да, глючила, да, была ненадежной. Но с тех пор прошло много времени.

    Да. Не понимал, не умел, удалял. Но разобрался, во-многом благодаря тому, что не ходил на сайт ESP8266.ru.

    Дело привычки. И, главное, проекты на МК - это не многотомные проекты для ПК.
    В этом шутливом топике (тесте на выявление угрюмых личностей) я показываю не все подходы. Использую три типа глобальных переменных, собранных в три таблицы:
    • таблица на запись параметров для удержания в памяти в случае потери питания;
    • таблица текущих рабочих параметров;
    • таблица отчетности;
    Остальное - локальные.
    Луа позволяет командой
    Код (C++):
    table.foreach(_G, print)
    увидеть список всех глобальных переменных - это шаблонное действие. Как можно в них запутаться после этого? Где Вы видели такую возможность в Сях?

    Спасибо! Я ничуть не подталкиваю к какому-то выбору.
    Я просто показываю определенные преимущества для обычного самодельщика (не электронщика, не программиста) такой работе с ESP-8266.

    И, да! Луа написан на Си - Си всему голова.
     
    Ujine нравится это.
  13. ИгорьК

    ИгорьК Гуру

    Бонус для нехмурых.
    Код (Lua):
    do
    print("\n\n\n\n\n\n\n\n\n\n\n\n\n=========== _G table: ===========")
    table.foreach(_G, print)
    print("===== package.loaded table: =====")
    table.foreach(_G.package.loaded, print)
    print("=================================")
    end
    Забиваете этот код в сниппеты, и всегда знаете что у вас творится в памяти.
    Увидев что-то за пределами восьми стандартных переменных в "_G" - глобалс, отыскиваете в коде и пытаетесь облокалить.

    Или не пытаетесь, если все идет по плану.


    В правом окне структура глобальных переменных после reset:

    блинк10.png

    Вот как это работает:

    Запускаем на исполнение файл - любой, ваш скрипт. Здесь У меня пример - setmqtt.lua, который, в свою очередь, задействует еще два выделенных файла.
    блинк11.png

    После выполнения своих задач скриптами, проверяем состояние глобальных переменных и делаем выводы:
    блинк12.png

    Этот простой проверочный сниппет очень важен для разработки программ, состоящих из многих файлов.

    Сниппет позволяет выловить все висящие в памяти потерянные переменные. Раскладывание их в локальные функции позволяет существенно снизить затраты памяти да и не запутаться в целом.

    Понимаю, что сейчас важность этого неочевидна, но время придет. Просто запомните что сниппет существует.

    Продолжение.
     
    Последнее редактирование: 19 янв 2018
    tpolimer и Ujine нравится это.
  14. где же там С ?
    там даже тип переменных не указан.

    та что вам так мой бложик покоя не дает?
     
  15. ИгорьК

    ИгорьК Гуру

    Разъясняю. Там идет подряд три кода:
    Код А
    Код В
    Код С

    Они все на Луа и искать там язык Си бессмысленно.

    Дык... Я по-дужески - рекламирую! Прямо ссылку даю.
     
  16. asda

    asda Нерд

    Жаль. Там хоть можно было понятную песенку про овощи послушать, со знакомыми ей поделиться,
    а здесь снова про непонятные esp и lua...
    Для поклонниц добавляйте, пожалуйста, что-нибудь этакое, розовое :), раз во флудилке.
     
  17. Airbus

    Airbus Радиохулиган Модератор

    А есть для Луны компилятор под AVR?
     
  18. ИгорьК

    ИгорьК Гуру

    Не встречал.
     
  19. Airbus

    Airbus Радиохулиган Модератор

    Тогда неинтересно.А так посмотрел сама идея очень даже ничего.Есть интересные плюшки.Это чтото типа java?
     
  20. ИгорьК

    ИгорьК Гуру

    ESP-8266 успешно заменяет ардуино когда хватает ног - в чем проблема?

    А говоришь посмотрел...