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

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

  1. ИгорьК

    ИгорьК Гуру

    О какой, интересно, прошивке идет речь? В последней, что я выкладывал, есть SPI, ибо у меня часы с ним работают. Или я что-то не понимаю?
     
  2. ИгорьК

    ИгорьК Гуру

    В любой есть, ибо вещь базовая.
     
  3. RotaryF

    RotaryF Нерд

    "... Я же воспользовался Вашей прошивкой из поста #776 ..."
    Поскольку состава модулей я не вижу ни в PuTTY, ни в ESPlorer, то ориентируюсь на диагностику при выполнении программули, задействующей этот самый SPI для работы с SD-карточкой.
    Пример взят из NodeMCU-доки, работает на моей 8266, ноги ESP32 подключил правильно, SD-карточки теже (и просто микро, и та, что НС).
    Получив nil на setup() работающего примера из букваря, я считаю, что модуля SPI у меня нет.
    ErrSPI-32.png
     
  4. ИгорьК

    ИгорьК Гуру

    Вы не тот букварь читаете.
    Ну нет так нет.
     
  5. RotaryF

    RotaryF Нерд

  6. ИгорьК

    ИгорьК Гуру

    Спасибо.
     
  7. RotaryF

    RotaryF Нерд

    А какой читаете Вы, какой надо?
    Как увидеть состав модулей, как получить/собрать нужный набор, ... :confused:
     
  8. ИгорьК

    ИгорьК Гуру

    Читать надо это: https://nodemcu.readthedocs.io/en/dev-esp32/

    Лучше собирать прошивку самому.
    И, я, честное слово, ни в чем не виноват.
     
  9. ИгорьК

    ИгорьК Гуру

    В этой прошивке есть SPI и он работает.
     
  10. Ferdinand

    Ferdinand Нерд

    Как мне привязать к кнопке следующие скрипты:


    Код (Text):

    wire1 = 8
    wire2 = 7
    wire3 = 6
    wire4 = 5

    _delay = 700 --delay in between two steps. minimum delay more the rotational speed

    gpio.mode(wire1, gpio.OUTPUT)--set four wires as output
    gpio.mode(wire2, gpio.OUTPUT)
    gpio.mode(wire3, gpio.OUTPUT)
    gpio.mode(wire4, gpio.OUTPUT)

    function sequence(a, b, c, d)--four step sequence to stepper motor
        gpio.write(wire1, a)
        gpio.write(wire2, b)
        gpio.write(wire3, c)
        gpio.write(wire4, d)
        tmr.delay(_delay)
    end

    while true do
        for i = 1 ,24 do --Rotation in one direction
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.HIGH)
            sequence(gpio.LOW, gpio.LOW, gpio.LOW, gpio.HIGH)
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.HIGH)
        end
        sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
    end

    Код (Text):

    wire1 = 8
    wire2 = 7
    wire3 = 6
    wire4 = 5

    _delay = 2000 --delay in between two steps. minimum delay more the rotational speed

    gpio.mode(wire1, gpio.OUTPUT)--set four wires as output
    gpio.mode(wire2, gpio.OUTPUT)
    gpio.mode(wire3, gpio.OUTPUT)
    gpio.mode(wire4, gpio.OUTPUT)

    function sequence(a, b, c, d)--four step sequence to stepper motor
        gpio.write(wire1, a)
        gpio.write(wire2, b)
        gpio.write(wire3, c)
        gpio.write(wire4, d)
        tmr.delay(_delay)
    end
    while true do
        for i = 1 ,24 do --Rotation in opposite direction
            sequence(gpio.LOW, gpio.LOW, gpio.LOW, gpio.HIGH)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.HIGH)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.HIGH)
        end
        sequence(gpio.LOW, gpio.LOW, gpio.LOW, gpio.HIGH)
    end
    Суть в том, что бы по кнопке степпер крутился в одну сторону и в другую.
    Пробовал реализовать с помощью посыла команд
    dofile("stepper_down.lua")
    dofile("stepper_up.lua")
    но чувствую.... - это тупик (
     
  11. ИгорьК

    ИгорьК Гуру

    Где вы взяли эти чудесные скрипты?
     
  12. ИгорьК

    ИгорьК Гуру

    По моему мнению, эти скрипты в принципе не работоспособны, почему - я писал в пункте 32.
     
  13. ИгорьК

    ИгорьК Гуру

    Посмотрел ваши сообщения, вы уже задавали вопрос на тему шаговых двигателей и получили вот такую ссылку. Судя по вашему скрипту, вы просто повторили на Lua код, что дан в заметке.

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

    К (практической) неработоспособности кода из статьи вы добавили ковенанты NodeMCU Lua: любой "тормоз" свыше 500 мс будет уничтожен ватчдогом, а любой цикл свыше 15 мс разрушит wifi.

    Я предполагаю, вы хотите научиться и сделать управление шторами/жалюзи etc. по wifi?

    Если упор здесь на слове "сделать" то лучше найти и повторить какой-нибудь проект на ардуино (про, нано) с получением управляющих команд от esp-8266 на модуле типа esp-1 по UART.

    Если упор на слове "научиться" - вам придется внимательнее читать эту тему. Я бы с удовольствием выложил для вас готовый код, но ни разу не работал с шаговым двигателем и у меня его нет. И, к сожалению, нет времени изучать ESP на этот предмет.

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

    Полагаю, вам нужен вот такой драйвер. (Все варианты: https://3d-diy.ru/catalog/drivers-stepper-motor/) Тогда вы без труда напишите под него код.

    В статье по этой ссылке также применяется delay() - если хотите, чтобы работал wifi - вам придется обойтись без нее. Это несложно - запускаете таймер, и он необходимое количество раз дергает пин STEP.
     
    Последнее редактирование: 28 авг 2019
  14. Ferdinand

    Ferdinand Нерд


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

    Реализация исключительно на Lua;

    Система должна считать свои шаги, для отслеживания своего положения (например 100 шагов вверх от -0 это открытие всего окна, 100 шагов вниз от +0 это закрытие всей площади окна, 70 шагов вниз от +0 - это образование щелки в 30 шагов снизу);

    Управление 2-мя кнопками ВВЕРХ и ВНИЗ, со следующей логикой: При нажатии ВВЕРХ, при условии что штора находится в положении -0, она откручивает 100 шагов и останавливается, сменяя положение на +0. Но вот если в процессе движения нажать ещё раз ВВЕРХ, то штора остановится и будет ожидать новой команды;

    Датчики, которые приходят на ум, и которые используются в подобных проектах, не рассматриваю.
    Хочется задействовать мат.расчеты и добиться от контроллера логических вычислений, не используя лишнее железо, думал "головой", а не обрабатывал сенсоры.
    __________________

    Двигатель 28BYJ-48 и драйвером ULN2003, были выбраны случайно. Под них и писались вышеупомянутые скрипты с каких-то статей по Ардуино, ибо к сожалению, lua не так популярны среди занавесачников.
    Двигатель заставил крутиться в обе стороны, правда его обороты удручают, но вот с логикой все застопорилось.

    И пользуясь случаем, хотелось бы узнать Ваше мнение, имеется ли принципиальная разница в драйвере указанном Вами и моим.
    Спасибо!
     
  15. ИгорьК

    ИгорьК Гуру

    Разница принципиальная, вам надо самому разобраться
     
  16. Ferdinand

    Ferdinand Нерд

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

     
  17. ИгорьК

    ИгорьК Гуру

    44. От Ардуино к Lua.

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

    Перепишем один из скриптов, что в посте #811, ибо это пример кода любого начинающего ардуинщика.

    Код (Lua):
    wire1 = 8
    wire2 = 7
    wire3 = 6
    wire4 = 5

    _delay = 700 --delay in between two steps. minimum delay more the rotational speed

    gpio.mode(wire1, gpio.OUTPUT)--set four wires as output
    gpio.mode(wire2, gpio.OUTPUT)
    gpio.mode(wire3, gpio.OUTPUT)
    gpio.mode(wire4, gpio.OUTPUT)

    function sequence(a, b, c, d)--four step sequence to stepper motor
        gpio.write(wire1, a)
        gpio.write(wire2, b)
        gpio.write(wire3, c)
        gpio.write(wire4, d)
        tmr.delay(_delay) -- Все стоит колом!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    end

    while true do
        for i = 1 ,24 do --Rotation in one direction
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.HIGH)
            sequence(gpio.LOW, gpio.LOW, gpio.LOW, gpio.HIGH)
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.HIGH)
        end
        sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
    end

    1. Начинающие (обоснованно) пропускают мимо ушей тот факт, что в Lua (условно, глобально) существует два типа данных: ссылочные и все остальные.

    upload_2019-9-11_9-7-48.png

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

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

    Таблицы! Везде применяем таблицы! Это должно войти в кровь!

    Давайте посмотрим на начало скрипта:
    Код (Lua):
    wire1 = 8
    wire2 = 7
    wire3 = 6
    wire4 = 5

    gpio.mode(wire1, gpio.OUTPUT)
    gpio.mode(wire2, gpio.OUTPUT)
    gpio.mode(wire3, gpio.OUTPUT)
    gpio.mode(wire4, gpio.OUTPUT)
    Что здесь плохо? Имеем четыре глобальные переменные, каждой из которых выделено свое имя. Это затратно. Загоняем их в таблицу и устанавливаем режим работы через оператор for ... do.

    Код (Lua):
    local pins = {8,7,6,5}
    for i = 1, #pins do
        gpio.mode(pins[i], gpio.OUTPUT)
    end
    2. Посмотрим на код в целом. Здесь мы видим, что автор 100500 раз чем-то кормит МК. Что такое gpio.HIGH, gpio.LOW?

    По коду, именно эта хрень пишется в ноги МК. Неужели вот прямо так и пишется?

    Давайте попробуем напечатать эти странные gpio.HIGH, gpio.LOW, авось получится. Ну не получится - шут с ним:
    Код (Lua):
    print(gpio.HIGH, gpio.LOW)
    Опс:
    upload_2019-8-30_12-2-44.png

    То есть, вместо этих жутких буковок, можно писать нули и единицы! (Ну кто бы подумал)

    3. Теперь поглядим на код совсем в целом. В цикле, с перерывами 700 мс, МК дергает свои ноги.
    Вот эта часть кода формирует задание:
    Код (Lua):
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.LOW)
            sequence(gpio.HIGH, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.LOW, gpio.LOW)
            sequence(gpio.LOW, gpio.HIGH, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.LOW)
            sequence(gpio.LOW, gpio.LOW, gpio.HIGH, gpio.HIGH)
            sequence(gpio.LOW, gpio.LOW, gpio.LOW, gpio.HIGH)
            sequence(gpio.HIGH, gpio.LOW, gpio.LOW, gpio.HIGH)
    Эта последовательность, на самом деле нулей и единиц, и пишется в МК. Помним, что таблицы Lua - лучшее что придумало человечество.

    Перепишем данные из кода, что выше, в таблицу:
    Код (Lua):
    local sequence = {
        1,0,0,0,
        1,1,0,0,
        0,1,0,0,
        0,1,1,0,
        0,0,1,0,
        0,0,1,1,
        0,0,0,1,
        1,0,0,1
    }
    Надеюсь, не ошибся.

    Вот эти байтики, построчно, с перерывом 700 мс надо кормить ногам.

    4. Чтобы жить было хорошо, нам нужны:
    • счетчик - какой раз (из 23) мы крутим нашу последовательность
    • счетчик/указатель - какая очередная группа из четырех элементов таблицы sequence будет пихаться ногам.
    • таймер, чтобы каждые 700 мс дергать ноги,
    • функция, которая на основании знания о последней записанной в ноги группе цифр из последовательности sequence будет писать в МК следующую четверку нулей и единиц:

    Код (Lua):
    local seqPointer = 1 -- Знает, где остановка в таблице sequence
    local steps = 1 -- Считает круги, что мы наматываем
    local move -- Это будет таймер, его надо сначала объявить как
    -- локальную переменную, иначе внутри скрипта его не будет видно
    move = tmr.create() -- Создаем таймер
    local dispatch  -- Это будет функция, которую дергает таймер

    -- функция записи в ноги МК четырех байт из таблицы
    local dopin = function()
        print('\n')
        -- от 1 до 4 - четыре повторения
        for i = 1, 4 do
            print("seqPointer: "..seqPointer,' ', "write pin: "..pins[i]..' => '..sequence[seqPointer],  "step: "..steps)
            -- Пишем данные
            gpio.write(pins[i], sequence[seqPointer])
            -- Сдвигаем указатель
            seqPointer = seqPointer + 1
        end
    end
     
    Последнее редактирование: 11 сен 2019
    swc нравится это.
  18. ИгорьК

    ИгорьК Гуру

    Идем дальше. Вот наш "управляющий":

    Код (Lua):
    -- Функция, которая всем управляет
    dispatch = function(t)
        -- seqPointer - указывает каую точно цифру из таблицы писать в ногу,
        -- его максимальное значение - 32, поэтому его надо периодически
        -- возвращать к единице
            if seqPointer == 33 then
            seqPointer = 1
            -- но возврат к единице означает, что сделан один "оборот",
            -- увеличиваем количество оборотов
            steps = steps + 1
        end
        -- Обороты тоже надо проверять, сколько там их максимум?
        -- Достигли сколько надо? Конец!
        if steps == 24 then
            -- Уничтожаем таймер
            t:stop()
            t:unregister()
            t = nil
            move = nil
            print('\n\nEnds writing pins!')
            -- Последний раз дергаем ноги (так у автора скрипта)
            dopin()
            return
        end
        -- Очередная запись в ноги МК
        dopin()
    end
    Запускаем таймер, и дергаем функцию dispatch с промежутком 700 мс:

    Код (Lua):
    -- Здесь третий аргумент (dispatch) - ссылка!!!! на функцию
    -- которую надо постоянно вызывать.
    move:alarm(700, 1, dispatch)
    И весь код, сравните со своим:
    Код (Lua):
    do
    local pins = {8,7,6,5}
    for i = 1, #pins do
        gpio.mode(pins[i], gpio.OUTPUT)
    end
    local sequence = {
        1,0,0,0,
        1,1,0,0,
        0,1,0,0,
        0,1,1,0,
        0,0,1,0,
        0,0,1,1,
        0,0,0,1,
        1,0,0,1
    }
    local seqPointer = 1
    local steps = 1
    local move
    move = tmr.create()
    local dispatch

    local dopin = function(t)
        print('\n')
        for i = 1, 4 do
            print("seqPointer: "..seqPointer,' ', "write pin: "..pins[i]..' => '..sequence[seqPointer],  "step: "..steps)
            gpio.write(pins[i], sequence[seqPointer])
            seqPointer = seqPointer + 1
        end
    end

    dispatch = function()
        if seqPointer == 33 then
            seqPointer = 1
            steps = steps + 1
        end
        if steps == 24 then
            t:stop()
            t:unregister()
            t = nil
            move = nil
            print('\n\nEnds writing pins!')
            -- seqPointer = 1
            dopin()
            return
        end
        dopin()
    end
    move:alarm(700, 1, dispatch)
    end
    И как это работает:

    upload_2019-8-30_12-59-25.png

    Подведем итог. В этом скрипте мы позволяем МК счастливо жить своей жизнью, и лишь один раз в 700 мс срабатывает таймер, проводит небольшие расчеты и в единственном цикле из четырех шагов устанавливает ноги в новое положение.
    Все остальное время МК свободен. То есть, мы можем грузить его еще какой-то работой.

    PS. Мы здесь не управляли шаговым двигателем, а переписывали код тов @Ferdinand

    UPD. В код закралась ошибочка, исправлено.

    Уничтожать таймер следует правильно.
    Ошибка:
    Код (Lua):
    dispatch = function()
    ...
        if steps == 24 then
            move:stop()
            move:unregister()
            move = nil
    ...
    end
    Надо:
    Код (Lua):
    dispatch = function(t)
    ...
        if steps == 24 then
            t:stop()
            t:unregister()
            t = nil
    -- Если таймер был в глобальной зоне, то обязательно,
    -- в остальных случаях - тоже не помешает:
            move = nil
    ...
    end
     
    Последнее редактирование: 2 сен 2019
    swc нравится это.
  19. swc

    swc Нерд

    Красиво!
     
  20. ИгорьК

    ИгорьК Гуру

    Здесь прошивка и код работы в терминале для устройства ESP32+MTRF64 nooLite.
     

    Вложения:

    • esp32.zip
      Размер файла:
      596,1 КБ
      Просмотров:
      156
    • __testMTRF.zip
      Размер файла:
      1,6 КБ
      Просмотров:
      119