Уровень сложности: для начинающих.
Идея возникла, когда под новый год сломалась старая гирлянда. Сын посмотрел на RGB-светодиодную ленту и спросил, можно ли сделать из нее гирлянду. Можно — сказал я, и сын начал долго описывать, как именно должна мигать гирлянда. Я ничего не понял, и решил сделать так, чтобы он мог сделать так как он хочет самостоятельно. Начал я с анализа собственных пожеланий к проекту:
- Графическая среда разработки типа Scratch
- offline работа — возможность работы устройства при выключенном компьютере
- Работа по воздуху, без подключения провода
- Надежность — никакая загруженная программа не должна «повесить» устройство до необходимости перезагрузки
Аппаратная платформа
За основу была взята плата ESP8266 c NodeMCU (вроде такой), к ней добавилась пара транзисторов и резисторов. Выбранные модули имеют регулятор напряжения на 3-20 вольт, что позволяет питать его от того же источника, что и ленту. Выходы esp дают напряжение 3 вольта с предельным током в 12mA, так что для управления лентой я использовал обычные биполярные транзисторы.
Чтобы из микроконтроллера не вышел белый дым, я поставил между выходом и базой резистор в 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-а.
В отличие от 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)
dernuss
30.12.2017 10:20А лучше использовать полевой транзистор, н канальный. Тогда не надо этого резистора;)
da-nie
30.12.2017 10:39Всё не так просто. :) Если у автора там ШИМ, то стоит посчитать ток на перезарядку ёмкости полевого транзистора с учётом частоты переключения. Может оказаться, что ток тоже будет приличный и тогда обязательно всплывёт и резистор в цепи затвора. :)
Кстати, полевик тоже потребуется выбрать с напряжением открывания, доступным автору. :)
farafonoff Автор
30.12.2017 11:19+1У меня в распоряжении были ifr530(для ардуины брал). 3.3 вольта им маловато.
dernuss
30.12.2017 11:31Согласен. Сейчас полным полно logic level.
Я кстати собираюсь сделать нечто похожее, только на esp32 и на 16 каналов. И сразу с источником питания ампер на 20;) Правда я очень давно собираюсь…farafonoff Автор
30.12.2017 11:38Это надо делать быстро, хотя бы один шаг за вечер. Многие штуки я хотел годами, а проблем было на 3 дня.
Dmitry_7
30.12.2017 16:46-1Как же сложно стало программировать. Чтобы просто помогать диодом, надо исследовать сто фреймворков да дюжину серверов. И в результате получить забагованное нечто, что упадет просто от обновления версии любого компонента.
Работа с выводными регистрами через шину ИСА, как я помню, была намного проще и понятнее.
Ig_B
30.12.2017 19:41Проще, если спаять декодер адреса и и добавить регистр для записи по этому адресу…
da-nie
Что-то больно мало. :) Какой у вас запланированный базовый ток (ток коллектора (гирлянды) на h21э поделите (h21э сильно плавает, но для расчёта подойдёт) и его примерно получите)? Вот исходя из этого тока и выберите базовый резистор (не забывая, что на открытом база-эмиттерном переходе падает около 0.6 В). Иначе ваш микроконтроллер зря напрягается на нагрев транзистора. :)
uterr
а я вот одного не пойму, неужели вот эти странные схемки-конструкторы правда понятней ребенку, чем просто программа на ардуине?
nochkin
Сильно зависит от возраста и уровня подготовки. Например, для 5-7 лет блок-схема проще и нагляднее, чем чистый код на С.