image

Уровень сложности: для начинающих.

Идея возникла, когда под новый год сломалась старая гирлянда. Сын посмотрел на RGB-светодиодную ленту и спросил, можно ли сделать из нее гирлянду. Можно — сказал я, и сын начал долго описывать, как именно должна мигать гирлянда. Я ничего не понял, и решил сделать так, чтобы он мог сделать так как он хочет самостоятельно. Начал я с анализа собственных пожеланий к проекту:

  1. Графическая среда разработки типа Scratch
  2. offline работа — возможность работы устройства при выключенном компьютере
  3. Работа по воздуху, без подключения провода
  4. Надежность — никакая загруженная программа не должна «повесить» устройство до необходимости перезагрузки


Аппаратная платформа


транзисторы

За основу была взята плата ESP8266 c NodeMCU (вроде такой), к ней добавилась пара транзисторов и резисторов. Выбранные модули имеют регулятор напряжения на 3-20 вольт, что позволяет питать его от того же источника, что и ленту. Выходы esp дают напряжение 3 вольта с предельным током в 12mA, так что для управления лентой я использовал обычные биполярные транзисторы.

image

Чтобы из микроконтроллера не вышел белый дым, я поставил между выходом и базой резистор в 220 Ом. У esp программный pwm, некоторые пины имеют специальное назначение, я подбирал экспериментально.

Прошивка


Перед использованием, esp8266 нужно прошить, я использую NodeMCU с lua, хотя она и имеет несколько меньше возможностей, чем Arduino с C++. Итак, проще всего начать с готовой прошивки с nodemcu-build.com. Для нашего проекта нужно будет добавить модуль pwm. Через некоторое время на почту упадет ссылка на образ. Нужно взять тот, что с float.

Прошить можно любым программатором отсюда, а я использую NodeMCU Flasher.

В NodeMCU есть файловая система, выполнение начинается с модуля init.lua, для загрузки я использую ESPlorer.

Мигаем диодом


В заблуждение меня ввел следующий момент. Внутренняя нумерация (GPIO0-16) используется только в native программах (Arduino/C++). Из lua используются обозначения с платы. Например, чтобы использовать GPIO16/D0(встроенный светодиод). из Lua, нужно писать gpio.write(0, gpio.HIGH). Помигать диодом можно прямо из консоли ESPlorer-а.

image

В отличие от Arduino, в nodemcu нельзя использовать delay и busy-loop, консоль и wifi используют для работы тот же самый процессор. Также в плату встроен watchdog, который перезагрузит ее если ваш код будет выполняться больше 500ms. Рекомендуется не занимать процессор больше чем на 2ms. Для решения проблемы существуют функции node.task.post и tmr

Выбор среды разработки


Сначала хотел использовать Scratch, но он не подошел мне, так как не позволяет работать оффлайн — программа исполняется на компьютере в среде scratch, а все платы для него работают пассивно. Пошарив в интернете, я наткнулся на Google Blockly. Это оказалось ровно тем, что нужно: он поддерживает кодогенерацию в lua, и создание собственных блоков. После экспериментов, я решил делать свой проект на основе web, выбрал nodejs в качестве сервера, и Blockly в качестве фронтенда. Абсолютно необходимо было создать 2 блока — установка цвета и задержка. Blockly имеет встроенные функции для работы с цветами в формате #ffffff, создание функции для установки цвета не составило никакой проблемы.

Заголовок спойлера
Blockly.Lua['set_color'] = function (block) {
    var parseColor = Blockly.Lua.provideFunction_(
        'set_colour_rgb',
        ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(s)',
            '  local rs,gs,bs = s.match(s, "#(..)(..)(..)");',
            '  setColor(tonumber(rs, 16),tonumber(gs, 16),tonumber(bs, 16));',
            'end']);
    var value_color = Blockly.Lua.valueToCode(block, 'Color', Blockly.Lua.ORDER_ATOMIC);
    var code = `set_colour_rgb(${value_color})\n`;
    return code;
};


Таким образом были закрыты 2 из 3х требований.

Функция sleep()


Тут пришлось конкретно подумать, как совместить надежную работу OTA с выполнением пользовательского кода. К счастью в lua есть библиотека coroutine

После раздумий и вдумчивого чтения документации я понял, что весь клиентский код нужно запускать в coroutine, и использовать yield вместо sleep, чтобы основной модуль мог установить таймер.

Также, для защиты платы от бесконечного цикла, я запатчил код после генератора, вставив yield(0) в начале каждой итерации каждого цикла

function MCUPostProcessLua(code) {
    return code.replace(/ do[ ]?\n/, ' do \ncoroutine.yield(0);\n');
}

OTA загрузка


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

Результат


github.com/farafonoff/BlocklyESP8266


Можно добавить очень много, например какую-то возможность авторизации для работы через публичные сети, user-friendly настройщик в режиме hostap, улучшить модульность init.lua и поддержку его обновления OTA (сейчас обновляется только модуль с загруженной программой).

Комментарии (18)


  1. da-nie
    30.12.2017 09:41
    +2

    я поставил между выходом и базой резистор в 220 Ом.


    Что-то больно мало. :) Какой у вас запланированный базовый ток (ток коллектора (гирлянды) на h21э поделите (h21э сильно плавает, но для расчёта подойдёт) и его примерно получите)? Вот исходя из этого тока и выберите базовый резистор (не забывая, что на открытом база-эмиттерном переходе падает около 0.6 В). Иначе ваш микроконтроллер зря напрягается на нагрев транзистора. :)


    1. uterr
      30.12.2017 15:29
      +1

      а я вот одного не пойму, неужели вот эти странные схемки-конструкторы правда понятней ребенку, чем просто программа на ардуине?


      1. nochkin
        30.12.2017 16:52

        Сильно зависит от возраста и уровня подготовки. Например, для 5-7 лет блок-схема проще и нагляднее, чем чистый код на С.


  1. dernuss
    30.12.2017 10:20

    А лучше использовать полевой транзистор, н канальный. Тогда не надо этого резистора;)


    1. da-nie
      30.12.2017 10:39

      Всё не так просто. :) Если у автора там ШИМ, то стоит посчитать ток на перезарядку ёмкости полевого транзистора с учётом частоты переключения. Может оказаться, что ток тоже будет приличный и тогда обязательно всплывёт и резистор в цепи затвора. :)
      Кстати, полевик тоже потребуется выбрать с напряжением открывания, доступным автору. :)


      1. dernuss
        30.12.2017 10:57

        Там меньше 1 МГц.


        1. da-nie
          30.12.2017 12:05

          Даже если 100 кГц, то нужный ток может составлять амперы (зависит от входной ёмкости транзистора). А вообще, с ШИМ лучше на полевики (точнее, мы ведь говорим о MOSFET, как я понимаю?) ставить драйвера.


          1. dernuss
            30.12.2017 12:18

            Да это всего навсего преобразователь уровня;)


            1. da-nie
              30.12.2017 12:28

              Нет. Это всего-навсего усилитель мощности. :) Прежде всего он обеспечивает большой ток выхода на затвор транзистора. А уровень может и не трогать (входит 12 В — выходит 12 В).


              1. dernuss
                30.12.2017 12:33

                Я про статус транзистора в схеме;)


              1. dernuss
                30.12.2017 12:44

                Я чёт перед НГ невнимательный. Думал используется лента на ws2812. Вы правы.


    1. farafonoff Автор
      30.12.2017 11:19
      +1

      У меня в распоряжении были ifr530(для ардуины брал). 3.3 вольта им маловато.


      1. dernuss
        30.12.2017 11:31

        Согласен. Сейчас полным полно logic level.
        Я кстати собираюсь сделать нечто похожее, только на esp32 и на 16 каналов. И сразу с источником питания ампер на 20;) Правда я очень давно собираюсь…


        1. farafonoff Автор
          30.12.2017 11:38

          Это надо делать быстро, хотя бы один шаг за вечер. Многие штуки я хотел годами, а проблем было на 3 дня.


  1. farafonoff Автор
    30.12.2017 11:37

    [del]


  1. Dmitry_7
    30.12.2017 16:46
    -1

    Как же сложно стало программировать. Чтобы просто помогать диодом, надо исследовать сто фреймворков да дюжину серверов. И в результате получить забагованное нечто, что упадет просто от обновления версии любого компонента.


    Работа с выводными регистрами через шину ИСА, как я помню, была намного проще и понятнее.


    1. farafonoff Автор
      30.12.2017 17:18

      Под эту плату есть ардуино. Цель была сделать среду вроде scratch.


    1. Ig_B
      30.12.2017 19:41

      Проще, если спаять декодер адреса и и добавить регистр для записи по этому адресу…