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

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

  1. ИгорьК

    ИгорьК Давно здесь

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

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

    Однако, есть проблема: https://geektimes.ru/post/297829/
    Тогда - паяльник.

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

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

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

    Большая засада. Приучитесь думать событийно-асинхронно - возвращаться к Си будет влом. Ну, не страшно - Python на Малине будет интереснее и понятнее.

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

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

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

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

    Вот ссылка - там три урока. Изучите и возвращайтесь с заряженной платой: http://www.emc-problem.net/проекты/...-подключить-отладочную-плату-nodemcu-esp8266/

    Заметим, что в 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
    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. Освещение на улице. (Для начинающих)
    ===================================
     

    Вложения:

    Последнее редактирование: 10 окт 2018 в 10:38
    ДедВова, SmileOfFortune, Ujine и 6 другим нравится это.
  2. ИгорьК

    ИгорьК Давно здесь

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

    30. Часы на MAX7219.
    31. Модуль для MAX31855
    32. Про while, tmr.now(), tmr.delay(). (Начинающим читать в первую очередь!)
    33. Фича MQTT.
    34. Немного про ds18b20.

    Просто: http://tylerneylon.com/a/learn-lua/
    ==============================================================================

    Шаг второй.

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

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

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

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

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

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

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

    Шаг третий.
     
    Последнее редактирование: 20 сен 2018
    Юра 80, ДедВова, vittka и 2 другим нравится это.
  3. ИгорьК

    ИгорьК Давно здесь

    Шаг третий.
    После прочтения немногих страниц уже можно открыть какую-нибудь дурацкую тему где много буков про 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.

    Теперь можно заново взглянуть на любой код на 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
    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
    А чтобы закрепить материал о таймере, прогуляйтесь сюда.
     
    Последнее редактирование: 30 апр 2018
    Mitrandir, ДедВова, SmileOfFortune и 5 другим нравится это.
  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
    Mitrandir, ДедВова, SmileOfFortune и 4 другим нравится это.
  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() возвращает два значения и первое нам не нужно.

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

    Что можно сделать с нашей задачей еще?
    Следующий шаг...
     
    Последнее редактирование: 10 ноя 2017
    ДедВова, 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);
    }
     
     
    Mitrandir, swc, ДедВова и 2 другим нравится это.
  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
    Ujine нравится это.
  14. Пушной звер

    Пушной звер Оракул

    где же там С ?
    там даже тип переменных не указан.

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

    ИгорьК Давно здесь

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

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

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

    asda Нуб

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

    Airbus Оракул

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

    ИгорьК Давно здесь

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

    Airbus Оракул

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

    ИгорьК Давно здесь

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

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