ESP, IoT LedBasic - Встроенный язык программирования световых эффектов для WS2812B на ESP8266

VktrSansara

✩✩✩✩✩✩✩
1 Дек 2018
13
8
Новомосковск
LedBasic — это интерпретируемый BASIC-подобный язык и виртуальная машина (VM) для создания анимаций на адресных светодиодных лентах. Программы пишутся в текстовом виде, компилируются в байт-код прямо на контроллере и выполняются неблокирующим образом — параллельно с остальным кодом Arduino.
Она позволяет писать анимации для светодиодов в виде простого текста (скриптов), компилировать их в компактный байт-код и воспроизводить без блокировки основного цикла микроконтроллера.

Основные возможности:
  • Неблокирующее выполнение— tick() вызывается из loop(), не мешает другим задачам
  • Независимость от типа ленты — подключение через коллбэки (совместимо с любой версией NeoPixelBus)
  • Полный язык: переменные A–Z, арифметика, условия, циклы, подпрограммы, функции
  • Управление скоростью—setSpeed(percent) масштабирует все задержки без изменения скрипта.
  • Встроенные LED-функции: SIN8, COS8, PIXEL, RND, ABS, MIN, MAX
  • HSV и RGB— SET_HSVс аппаратной конвертацией без float
  • Браузерная IDE — редактор, эмулятор, отладчик, экспорт
Особенности библиотеки:
  • Аппаратная независимость (Hardware Agnostic)
    LedBasic ничего не знает о железе. Она не использует напрямую FastLED или NeoPixelBus. При создании объекта вы передаете ей коллбэки (функции обратного вызова) для установки цвета пикселя, вывода буфера на ленту и очистки. Это значит, что вы можете использовать абсолютно любую библиотеку для работы со светодиодами.
  • Асинхронность (Неблокирующая работа)
    Внутри используется конечный автомат (State Machine). Команды WAIT или DELAY не вешают микроконтроллер (ESP8266/ESP32). Функция tick() быстро отрабатывает часть инструкций и отдает управление обратно, что позволяет параллельно работать с Wi-Fi, MQTT или веб-сервером.
  • Встроенная математика и эффекты
    Реализованы собственные таблицы синуса и косинуса (sin8, cos8) и конвертер HSV -> RGB. Библиотеке не нужны тяжелые зависимости.
  • Компиляция на лету и запуск из памяти
    Текстовый скрипт компилируется в компактный бинарный байт-код. Скрипты можно хранить в файловой системе (LittleFS) и запускать прямо оттуда.
  • Защита от зависаний (Watchdog protection)
    За один вызов tick() виртуальная машина выполняет не более 1000 инструкций. Если в BASIC-скрипте написан бесконечный цикл GOTO без пауз, микроконтроллер не зависнет и не уйдет в перезагрузку (Watchdog reset).

Особенности языка LedBasic:
  • Переменные и математика: 26 переменных (A-Z), поддерживающих 16-битные целые числа. Доступна базовая математика (+, -, *, /, %).
  • LED-команды: SET (RGB цвет), SET_HSV (цвет по тону, насыщенности и яркости), FILL (заливка), CLEAR (очистка), BRIGHT (яркость).
  • Отрисовка: Команды SHOW (вывести на ленту), WAIT (вывести и ждать), DELAY (просто пауза).
  • Математические функции: Встроены быстрые функции для создания эффектов: RND (случайное число), SIN8 и COS8 (табличные синусы/косинусы для плавных волн), MIN, MAX, ABS.
  • Управление потоком: Классические FOR...TO...STEP...NEXT, циклы IF...THEN, переходы GOTO и подпрограммы GOSUB...RETURN.
Скачать:
Библиотека на - GitVerse
Библиотека с - Яндекс.Диск
Мануалы и справочники - Яндекс.Диск
Дополнительно: Online LedBasic IDE

Можно ввести свое имя файла:
1773724062885.png
Переменные теперь всегда отображаются в отладке, те которые используются в коде выделяются:
1773724142975.png
1773724249530.png
Функции логически разделены на группы: инициализация, загрузка кода, управление выполнением и настройки.

Инициализация объекта:

LedBasic(uint16_t count, LBSetPixel setPixelCb, LBShow showCb, LBClear clearCb)
Конструктор класса.
Создает экземпляр виртуальной машины.
Библиотека не привязана к конкретному оборудованию, поэтому при создании объекта вы обязаны передать количество светодиодов и три функции-коллбэка (обычно это лямбда-выражения), которые "объясняют" библиотеке, как управлять вашей лентой.
  • Аргументы:
    • count — общее количество пикселей на вашей ленте.
    • setPixelCb — функция вида void(uint16_t pos, uint8_t r, uint8_t g, uint8_t b). Устанавливает цвет конкретного пикселя.
    • showCb — функция вида void(). Вызывает обновление ленты (отправку данных из буфера на светодиоды).
    • clearCb — функция вида void(). Полностью гасит ленту (заливает черным цветом).
~LedBasic() - Деструктор класса. Вызывается при удалении объекта. Автоматически освобождает динамическую память (RAM), если она была выделена под байт-код с помощью malloc.


Подготовка и компиляция скриптов:

bool compileFromText(const char* scriptText)

Компилирует текстовый скрипт на языке BASIC в бинарный байт-код прямо в оперативной памяти (RAM) микроконтроллера.
  • Аргументы: Строка const char*, содержащая полный текст скрипта (строки должны разделяться символом переноса \n).
  • Как работает: Парсит текст, переводит команды в числа (токены), выделяет нужное количество RAM и сохраняет туда байт-код. Строит индекс для быстрых переходов GOTO.
  • Возвращает: true при успешной компиляции, false если не хватило памяти.

bool compileBasToBin(const char* basPath, const char* binPath)
Читает текстовый файл BASIC из файловой системы LittleFS, компилирует его построчно и сразу записывает готовый байт-код в другой файл.
  • Аргументы:
    • basPath — путь к исходному текстовому файлу (например, "/effect.bas").
    • binPath — путь, куда сохранить бинарный файл (например, "/effect.bin").
  • Особенности: Очень экономит оперативную память, так как не загружает весь текст в RAM. Полезно для предварительной компиляции скриптов.

bool loadBinFile(const char* path)
Загружает в оперативную память заранее скомпилированный бинарный файл из файловой системы LittleFS.
  • Аргументы: path — путь к бинарному файлу (например, "/effect.bin").
  • Возвращает: true при успехе, false если файл не найден или ошибка чтения.

bool loadBinMemory(const uint8_t* code)
Подключает байт-код напрямую из указателя памяти.
  • Аргументы: code — массив uint8_t, содержащий байт-код.
  • Особенности: Эта функция не копирует массив в новую память и не вызывает malloc. Она просто сохраняет указатель. Это идеально подходит для хранения жестко зашитых (hardcoded) эффектов во Flash-памяти микроконтроллера с использованием PROGMEM.

Управление и выполнение:

void play()

Запускает выполнение загруженного скрипта с самой первой строки.
  • Как работает: Обнуляет все переменные (A-Z), сбрасывает стек вызовов (GOSUB, FOR), переводит виртуальную машину в статус VM_RUNNING. Если скрипт не загружен — функция просто проигнорируется.

void stop()
Останавливает выполнение скрипта.
  • Как работает: Переводит машину в статус VM_STOPPED и автоматически вызывает ваш коллбэк clearCb, чтобы выключить все светодиоды на ленте.

void tick()
Главная функция-движок.
Ее обязательно нужно поместить внутрь главного цикла loop() вашего скетча, чтобы анимация работала.
  • Как работает: За один вызов читает и выполняет порцию инструкций (байт-кода).
  • Асинхронность: Если в скрипте встречается команда WAIT 500, функция tick() запоминает время, переводит VM в режим ожидания и сразу же завершает свою работу, отдавая управление основному loop(). При следующих вызовах она будет проверять встроенный таймер (millis()), и продолжит работу только когда время выйдет.
  • Безопасность: Чтобы микроконтроллер не завис на конструкции вида 10 GOTO 10, tick() имеет лимит (budget): за один проход она выполняет максимум 1000 инструкций.

bool isRunning() const
  • Возвращает: true, если скрипт в данный момент выполняется (включая моменты паузы WAIT/DELAY). Возвращает false, если скрипт остановлен функцией stop() или дошел до конца программы (маркера конца файла).

Управление скоростью:
Библиотека позволяет "на лету" изменять скорость воспроизведения эффектов, воздействуя на длительность пауз WAIT и DELAY в скриптах, без необходимости переписывать сам код скрипта.

void setSpeed(uint16_t percent)
Устанавливает множитель скорости в процентах (от 1 до 1000).
  • Аргументы:percent — скорость в процентах.
    • 100 — нормальная скорость (по умолчанию, 1 к 1).
    • 200 — в 2 раза быстрее (задержка WAIT 100 превратится в 50 мс).
    • 50 — в 2 раза медленнее (задержка WAIT 100 превратится в 200 мс).

uint16_t getSpeed() const
  • Возвращает: текущую установленную скорость в процентах.
C++:
void setup() {
    strip.begin();

    // 1. Инициализация (basic создана глобально)

    // 2. Компиляция текста из строки
    basic.compileFromText("10 SET 0, 255, 0, 0\n20 WAIT 1000\n30 CLEAR\n40 WAIT 1000\n50 GOTO 10\n");

    // Можно загрузить из файла: basic.loadBinFile("/blink.bin");

    // 3. Запуск программы
    basic.play();
}

void loop() {
    // 4. Движок программы (не блокирует цикл!)
    basic.tick();

    // Пример управления на лету:
    // Если нажата кнопка, ускорить в 3 раза
    if (digitalRead(BTN_PIN) == LOW) {
        basic.setSpeed(300);
    } else {
        basic.setSpeed(100);
    }
}
Язык представляет собой классический диалект BASIC с номерами строк.

Типы данных и переменные
  • Поддерживается 26 глобальных целочисленных переменных (типа int16_t).
  • Имена переменных — одиночные заглавные буквы английского алфавита: от A до Z.
Команды управления светодиодами
  • SET pos, r, g, b — Установить цвет RGB (0-255) для пикселя с индексом pos.
  • SET_HSV pos, h, s, v — Установить цвет в формате HSV (Оттенок, Насыщенность, Яркость). Библиотека сама пересчитает это в RGB.
  • FILL r, g, b — Залить всю ленту одним цветом.
  • CLEAR — Выключить все светодиоды (залить черным).
  • SHOW — Отправить данные на ленту (применить изменения).
  • WAIT ms — Вызвать SHOW и подождать ms миллисекунд.
  • DELAY ms — Просто подождать ms миллисекунд (без обновления ленты).
  • BRIGHT val — Команда зарезервирована для изменения глобальной яркости.
Управление логикой (Control Flow)
  • GOTO line — Безусловный переход на строку с номером line.
  • GOSUB line ... RETURN — Вызов подпрограммы и возврат (глубина стека до 10 вызовов).
  • FOR var = start TO end [STEP step] ... NEXT var — Цикл со счетчиком (глубина вложенности до 8).
  • IF условие THEN команда — Условное выполнение. Поддерживаются операторы ==, !=, >, <, >=, <=. Особенность: после THEN может идти только одна команда.
Математика и функции
Поддерживается приоритет математических операций: +, -, *, /, % (остаток от деления), AND (побитовое И), OR (побитовое ИЛИ).
Встроенные функции:

  • RND(min, max) — Случайное число в диапазоне.
  • ABS(x) — Модуль числа.
  • MIN(a, b), MAX(a, b) — Минимальное / максимальное значение.
  • SIN8(x), COS8(x) — Быстрый синус/косинус (вход 0-255, выход 0-255).
  • PIXEL — Возвращает индекс последнего пикселя на ленте (общее количество - 1).
LedBasic IDE — это легковесная, полностью работающая (не без багов конечно, но вполне работает.) в браузере среда разработки (IDE) и эмулятор для написания эффектов адресных светодиодных лент (подобных WS2812b) на Basic подобном языке.

Основные возможности:
  • Синтаксическая подсветка: Автоматическое окрашивание команд (синий), логики (фиолетовый), математики (желтый), переменных (зеленый) и чисел.
  • Автодополнение (Autocomplete): При вводе текста появляются подсказки с шаблонами команд (например, при вводе SET предложит SET_HSV P , C , 255 , 200).
  • Анализ ошибок (Линтер): Редактор «на лету» проверяет код. Если допущена ошибка (неизвестная команда, нет номера строки), код подчеркивается красной волнистой линией, а в левом поле появляется значок предупреждения.
  • Инструмент «Нумерация»: Так как язык требует номеров строк (10, 20, 30...), этот инструмент позволяет автоматически перенумеровать весь код с заданным шагом.
  • Автоформатирование: Кнопка «Формат» автоматически расставляет пробелы вокруг операторов и приводит команды к верхнему регистру для красоты кода.
Встроенный LED эмулятор:
Позволяет видеть результат работы кода прямо на экране без подключения реального "железа".
  • Формы вывода:
    Поддерживает 3 режима визуализации:
    • Полоса (Strip) — классическая прямая лента.
    • Кольцо (Ring) — светодиоды по кругу.
    • Матрица (Matrix) — прямоугольная 2D-сетка (с настройкой ширины и высоты).
  • Настройки: Можно менять количество пикселей (до 1024), масштаб (размер светодиодов).
  • Графика: Реалистичное отображение с эффектом "свечения" (Glow) вокруг ярких пикселей.
  • Производительность: Показывает реальный FPS работы эмулятора.
Отладка и мониторинг:
  • Консоль: Выводит логи компиляции, сообщения об ошибках и статус системы.
  • Переменные (Live-мониторинг): В реальном времени показывает текущие значения всех 26 доступных переменных (от A до Z) прямо во время работы анимации! Отличный инструмент для поиска логических ошибок.
  • Байт-код: Показывает результат компиляции. Текстовый BASIC переводится в компактные HEX-инструкции, которые можно посмотреть с привязкой к номерам строк.
Экспорт и интеграция с микроконтроллерами (Ардуино / ESP):
Программа создана не только для развлечения, но и для реального использования в проектах (например, на Arduino или ESP8266/ESP32). Код можно экспортировать в несколько форматов:
  • .bas — исходный текстовый код программы.
  • const char* — код в виде C++ строки для вставки прямо в скетч Arduino.
  • PROGMEM — код в виде массива символов, хранящегося во флеш-памяти микроконтроллера.
  • .bin hex — скомпилированный бинарный байт-код в виде C++ массива (uint8_t), готовый для выполнения на микроконтроллере (самый быстрый и компактный вариант).
Удобство интерфейса (UI/UX):
  • Горячие клавиши: Ctrl+Enter или F5 для запуска кода, Ctrl+S для сохранения.
  • Кастомизация UI: Можно изменять высоту нижней панели отладки и ширину левой панели эмулятора перетаскиванием мыши.
  • Настройки: Подстройка размера шрифта, размера табуляции (Tab), скорости работы виртуальной машины (setSpeed (%)).
  • Локальная работа: Все функции (загрузка, сохранение файлов, компиляция) работают прямо в браузере с использованием HTML5 File API, не требуя сервера.
2026-03-12_23-08-40.png2026-03-12_23-08-28.png
C++:
// =============================================================
//  main_rainbow.cpp — эффект «Радуга со случайными вспышками»
//
//  Вся лента показывает полный спектр радуги, равномерно
//  распределённый по длине. Радуга медленно вращается.
//  Случайные пиксели вспыхивают белым — как искры.
//
//  Использует PIXEL — автоматически подстраивается под
//  любую длину ленты без изменения скрипта.
//
//  Железо: лента WS2812B, ESP8266, DMA-пин GPIO3 (RX)
// =============================================================

#include <Arduino.h>
#include <NeoPixelBus.h>
#include "LedBasic.h"

// --- настройки ---
#define NUM_LEDS  60    // меняй под свою ленту
#define DATA_PIN   3    // DMA: только GPIO3 (RX)

using MyStrip = NeoPixelBus<NeoGrbFeature, NeoEsp8266DmaWs2812xMethod>;
MyStrip strip(NUM_LEDS, DATA_PIN);

LedBasic basic(
    NUM_LEDS,
    [](uint16_t pos, uint8_t r, uint8_t g, uint8_t b) {
        strip.SetPixelColor(pos, RgbColor(r, g, b));
    },
    []{ strip.Show(); },
    []{ strip.ClearTo(RgbColor(0, 0, 0)); strip.Show(); }
);

// =============================================================
//  Скрипт: радуга + случайные белые вспышки
//
//  H  — смещение оттенка (анимация вращения)
//  P  — текущий пиксель
//  C  — оттенок пикселя P
//  S  — случайное число для вспышки (0..14)
//
//  Каждый пиксель получает оттенок H + P * 256 / PIXEL —
//  это равномерно растягивает весь спектр по ленте.
//  С вероятностью 1/15 пиксель вспыхивает белым.
// =============================================================
const char* scriptText =
    "10 H = 0\n"           // начальное смещение оттенка

    // --- кадр: рисуем радугу пиксель за пикселем ---
    "100 P = 0\n"
    "110 C = H + P * 256 / PIXEL\n"  // оттенок: смещение + шаг по позиции
    "120 SET_HSV P , C , 255 , 170\n"

    // с вероятностью 1/15 — белая вспышка поверх
    "130 S = RND 0 , 14\n"
    "140 IF S == 0 THEN SET P , 255 , 255 , 220\n"

    "150 P = P + 1\n"
    "160 IF P <= PIXEL THEN GOTO 110\n"

    // показать кадр и прокрутить радугу
    "170 WAIT 25\n"
    "180 H = H + 4\n"
    "190 IF H > 255 THEN H = H - 256\n"
    "200 GOTO 100\n";

// =============================================================
void setup() {
    strip.Begin();
    strip.Show();
    basic.compileFromText(scriptText);
    basic.play();
}

void loop() {
    basic.tick();
}

anim_prev.gif
C++:
10 H = 0
20 FOR I = 0 TO PIXEL
30   C = H + I * 256 / PIXEL
40   SET_HSV I , C , 255 , 180
50 NEXT I
60 WAIT 30
70 H = H + 2
80 IF H > 255 THEN H = H - 256
90 GOTO 20
000 0a730 07 40 31 00 00 0110 H = 0стр 10
1000 141010 30 08 40 31 00 00 11 66 0120 FOR I = 0 TO PIXELстр 20
2300 1e1530 02 40 30 07 50 30 08 52 31 01 00 53 66 0130 C = H + I * 256 / PIXELстр 30
4100 281523 30 08 02 30 02 02 31 00 ff 02 31 00 b4 0140 SET_HSV I , C , 255 , 180стр 40
5900 32413 30 08 0150 NEXT Iстр 50
6600 3c524 31 00 1e 0160 WAIT 30стр 60
7400 461030 07 40 30 07 50 31 00 02 0170 H = H + 2стр 70
8700 501814 30 07 43 31 00 ff 15 30 07 40 30 07 51 31 01 00 0180 IF H > 255 THEN H = H - 256стр 80
10800 5a516 31 00 14 0190 GOTO 20стр 90

C++:
// 118 bytes
const uint8_t rainbow_bin[] PROGMEM = {
  0x00, 0x0a, 0x07, 0x30, 0x07, 0x40, 0x31, 0x00,
  0x00, 0x01, 0x00, 0x14, 0x0a, 0x10, 0x30, 0x08,
  0x40, 0x31, 0x00, 0x00, 0x11, 0x66, 0x01, 0x00,
  0x1e, 0x0f, 0x30, 0x02, 0x40, 0x30, 0x07, 0x50,
  0x30, 0x08, 0x52, 0x31, 0x01, 0x00, 0x53, 0x66,
  0x01, 0x00, 0x28, 0x0f, 0x23, 0x30, 0x08, 0x02,
  0x30, 0x02, 0x02, 0x31, 0x00, 0xff, 0x02, 0x31,
  0x00, 0xb4, 0x01, 0x00, 0x32, 0x04, 0x13, 0x30,
  0x08, 0x01, 0x00, 0x3c, 0x05, 0x24, 0x31, 0x00,
  0x1e, 0x01, 0x00, 0x46, 0x0a, 0x30, 0x07, 0x40,
  0x30, 0x07, 0x50, 0x31, 0x00, 0x02, 0x01, 0x00,
  0x50, 0x12, 0x14, 0x30, 0x07, 0x43, 0x31, 0x00,
  0xff, 0x15, 0x30, 0x07, 0x40, 0x30, 0x07, 0x51,
  0x31, 0x01, 0x00, 0x01, 0x00, 0x5a, 0x05, 0x16,
  0x31, 0x00, 0x14, 0x01, 0x00, 0x00,
};

const uint8_t rainbow_bin_size = 118;
Если коротко:
РесурсESP8266ESP32
RAM (Общая)~1.5Kb~2Kb
Flash~6 - 10Kb~8 - 12Kb
Скорость (tick)Очень высокаяМгновенная

Оперативная память (RAM):
  • Статические:
    • Переменные A - Z: Массив занимает 52 байта.
    • Индекс строк: Массив LineEntry lineIndex[MAX_LINES]. Если MAX_LINES равен 128, при размере структуры 4 байта это займет 512 байт.
    • Стек вызовов: Массивы для FOR и GOSUB (стек возвратов и состояний циклов) еще 100 - 200 байт.
    • Служебные поля: Переменные состояния около 20 - 30 байт.
  • Динамические:
    • Байт-код: Зависит от размера вашего скрипта.
    • Коллбэки: std::function для вывода на ленту добавляет еще около 32 - 64 байт.
Итого RAM: Потребление VM составляет примерно 0.7 - 1.2 КБ + размер загруженного байт-кода.

Постоянная память (Flash):
  • Таблицы в PROGMEM:
    • _sin8_table: 256 байт.
  • Логика интерпретатора - займет примерно 4–8 КБ Flash.
  • Скрипты: Если вы храните их как текстовые исходники в коде, они занимают место как обычные строки.
Производительность CPU:
  • ESP32: Нет необходимости.
  • ESP8266: Лучше поднять до 160MHz
Например (PlatformIO):
INI:
; PlatformIO Project Configuration File
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:d1]
platform = espressif8266
board = d1
framework = arduino
board_build.f_cpu = 160000000L
board_build.filesystem = littlefs
board_build.flash_size = 4MB
board_build.flash_mode = qio
board_build.ldscript = eagle.flash.4m2m.ld
monitor_speed = 115200
lib_deps =
    makuna/NeoPixelBus@^2.8.4
 
Изменено:

SlavaZagaynov

★✩✩✩✩✩✩
27 Ноя 2019
248
46
www.youtube.com
О, круто. Я похожую по смыслу штуку делал, только с возможностью крутить 2 серво, играть мп3, выполнять встроенные команды, светить rgb светиками плавно и т.п. У меня называется "Сценарии".
 

VktrSansara

✩✩✩✩✩✩✩
1 Дек 2018
13
8
Новомосковск
Для примера, достаточно сложные эффекты можно сгенерировать, например, через DeepSeek, но ему придется скормить как минимум мануал и в случае ошибок указать на них. Самые частые ошибки у него были связаны с переменными, так как их может быть всего 26 штук, заглавные буквы латинского алфавита A–Z. А также со скобками, их нет, нужно использовать промежуточные переменные и приоритет выполнения операций: *, /, % выполняются раньше +, -.

Вот несколько сгенерированных примеров для матрицы (16х16), их можно запустить в Online LedBasic IDE
Правда не очень похоже на лаву из Майнкрафта, но эффект получился впечатляющий
anim_8_1.gif
C++:
' Переменные:
' A - размер матрицы
' B - время (основная фаза)
' C - время (вторичная фаза)
' D - X координата
' E - Y координата
' F - линейный адрес
' G - красный канал (R)
' H - зелёный канал (G)
' I - синий канал (B)
' J - soupHeat (основная "температура")
' K - flameHeat (для вспышек)
' L - potHeat (для пятен)
' M - случайное число для вспышек
' N - временная для расчётов

10 A = 16 'для матрицы 16х16
20 B = 0
30 C = 0
40 K = 0   ' flameHeat

100 B = B + 2
110 IF B > 255 THEN B = B - 256
120 C = C + 1
130 IF C > 255 THEN C = C - 256

' Случайная вспышка (как в оригинале: 0.5% шанс)
140 M = RND 0 , 200
150 IF M > 199 THEN K = 150

160 E = 0

170 D = 0

' Конвертация в линейный адрес (зигзаг)
180 F = E * A
190 N = E % 2
200 IF N == 1 THEN F = F + A - 1 - D
210 IF N == 0 THEN F = F + D

' ===========================================
' РАСЧЁТ ТЕМПЕРАТУРЫ (soupHeat)
' Алгоритм Minecraft: комбинация соседних пикселей
' ===========================================

' Базовый soupHeat от координат и времени
220 J = SIN8 D * 6 + B
230 J = J + SIN8 E * 6 + C
240 J = J / 2

' Добавляем влияние "соседей" (имитация 3x3 области)
250 J = J + SIN8 D * 4 + E * 4 + B * 2
260 J = J / 2

' flameHeat влияет на яркость (как в Minecraft)
270 J = J + K / 3
280 IF J > 255 THEN J = 255

' ===========================================
' РАСЧЁТ ЦВЕТА (формула Minecraft)
' red = colorHeat * 100 + 155
' green = colorHeat^2 * 255
' blue = colorHeat^4 * 128
' ===========================================

' Нормализуем J в диапазон 0-1 (в int16: 0-255 -> 0-255)
' colorHeat = J * 2, clamped 0-255

' Красный: base 155 + до 100
290 G = J * 100 / 255 + 155
300 IF G > 255 THEN G = 255

' Зелёный: colorHeat^2 * 255
' J*J/255 даёт квадрат в диапазоне 0-255
310 H = J * J / 255
320 H = H * 255 / 255   ' *1, но оставляем для ясности

' Синий: colorHeat^4 * 128
' J^4 = (J^2)^2
330 I = J * J / 255      ' J^2
340 I = I * I / 255      ' J^4
350 I = I * 128 / 255

' ===========================================
' СПЕЦИАЛЬНЫЕ ЭФФЕКТЫ MINECRAFT
' ===========================================

' Яркие пятна (имитация пузырей)
360 N = SIN8 D * 12 + E * 8 + B * 4
370 IF N > 220 THEN G = 255
380 IF N > 220 THEN H = H * 2
390 IF N > 220 THEN I = I / 2

' Тёмные прожилки (как в текстуре Minecraft)
400 N = SIN8 D * 3 + E * 5 + B
410 IF N < 50 THEN G = G - 40
420 IF N < 50 THEN H = H - 20

' Эффект "кипения" на поверхности
430 IF E == 0 THEN G = G + 30
440 IF E == 0 THEN H = H + 10

' Случайные яркие точки (как искры в лаве)
450 M = RND 0 , 255
460 IF M > 250 THEN G = 255
470 IF M > 250 THEN H = 200
480 IF M > 250 THEN I = 100

' ===========================================
' КОРРЕКЦИЯ ЦВЕТОВ
' ===========================================

' Проверка границ
490 IF G < 155 THEN G = 155
500 IF G > 255 THEN G = 255
510 IF H < 0 THEN H = 0
520 IF H > 255 THEN H = 255
530 IF I < 0 THEN I = 0
540 IF I > 128 THEN I = 128

550 SET F , G , H , I

560 D = D + 1
570 IF D < A THEN GOTO 180

580 D = 0
590 E = E + 1
600 IF E < A THEN GOTO 170

' Уменьшаем flameHeat (как в Minecraft: flameHeat - 0.06)
610 K = K - 15   ' примерно 0.06 * 255
620 IF K < 0 THEN K = 0

630 WAIT 30
640 GOTO 100
anim_2.gif
C++:
' Переменные:
' A - размер матрицы
' B - время
' C - X координата
' D - Y координата
' E - линейный адрес
' F - красный
' G - зелёный
' H - синий
' I - температура
' J - шум
' K - для пятен

10 A = 16 'для матрицы 16х16
20 B = 0

100 B = B + 3
110 IF B > 255 THEN B = B - 256

120 D = 0

130 C = 0

140 E = D * A
150 J = D % 2
160 IF J == 1 THEN E = E + A - 1 - C
170 IF J == 0 THEN E = E + C

' ===========================================
' БАЗОВАЯ ТЕКСТУРА ЛАВЫ
' ===========================================

' Температура от координат и времени
180 I = SIN8 C * 8 + B
190 I = I + SIN8 D * 8 + B * 2
200 I = I / 2 + 128

' Красный - всегда высокий
210 F = 255

' Зелёный - от температуры (как в Minecraft)
220 G = I - 100
230 IF G < 30 THEN G = 30
240 IF G > 200 THEN G = 200

' Синий - минимум
250 H = I / 4
260 IF H > 80 THEN H = 80

' ===========================================
' ПЯТНА (ХАРАКТЕРНАЯ ТЕКСТУРА MINECRAFT)
' ===========================================

' Большие пятна
270 J = SIN8 C * 4 + D * 4 + B
280 IF J > 200 THEN F = 255
290 IF J > 200 THEN G = G + 50
300 IF J > 150 THEN H = H / 2

' Мелкие детали
310 K = SIN8 C * 12 + D * 10 + B * 3
320 IF K > 220 THEN F = 255
330 IF K > 220 THEN G = G + 30

' Тёмные прожилки
340 J = SIN8 C * 3 + D * 3 + B * 2
350 IF J < 60 THEN F = F - 30
360 IF J < 60 THEN G = G - 20

' ===========================================
' ЭФФЕКТ ДВИЖЕНИЯ (ТЕЧЕНИЕ)
' ===========================================

' Имитация течения лавы вниз
370 IF D == 7 THEN F = 255
380 IF D == 7 THEN G = G + 40
390 IF D == 6 THEN F = F + 20
400 IF D == 6 THEN G = G + 10

' ===========================================
' ФИНАЛЬНАЯ КОРРЕКЦИЯ
' ===========================================

410 IF F > 255 THEN F = 255
420 IF F < 200 THEN F = 200
430 IF G > 230 THEN G = 230
440 IF G < 40 THEN G = 40
450 IF H < 0 THEN H = 0
460 IF H > 100 THEN H = 100

470 SET E , F , G , H

480 C = C + 1
490 IF C < A THEN GOTO 140

500 C = 0
510 D = D + 1
520 IF D < A THEN GOTO 130

530 WAIT 25
540 GOTO 100
anim_3.gif
C++:
10 T = 0
20 FOR I = 0 TO PIXEL
' 1. Превращаем индекс пикселя (0..255) в координаты X и Y (0..15)
30   X = I % 16
40   Y = I / 16

' --- ДЛЯ МАТРИЦ ЗМЕЙКОЙ (ZIGZAG) ---
' Если матрица спаяна зигзагом, уберите апострофы в строках 45 и 46:
' 45 Z = Y % 2
' 46 IF Z == 1 THEN X = 15 - X

' 2. Растягиваем координаты на масштаб 0..240 для плавности волны
50   X = X * 16
60   Y = Y * 16

' 3. ГЕНЕРИРУЕМ ВОЛНЫ
' Волна 1: Горизонтальная (движется вправо)
70   A = X + T
80   A = A % 256            ' Держим аргумент строго в рамках 0-255
90   H = SIN8 A

' Волна 2: Вертикальная косинусоида (движется вверх)
100  B = Y + 256            ' +256 спасает от отрицательных значений
110  B = B - T
120  B = B % 256
130  S = COS8 B
140  H = H + S              ' Складываем с первой волной

' Волна 3: Диагональная синусоида
150  C = X + Y
160  C = C + T
170  C = C % 256
180  S = SIN8 C
190  H = H + S              ' Складываем с предыдущими

' 4. Усредняем результат трех волн
' Три функции дали нам сумму от 0 до 765. Делим на 3, получаем Hue (0..255)
200  H = H / 3

' 5. Выводим пиксель: H - наш цвет плазмы, 255 - макс насыщенность и яркость
210  SET_HSV I , H , 255 , 255
220 NEXT I

' 6. Показываем кадр и сдвигаем время (T)
230 WAIT 25
240 T = T + 3
250 IF T > 255 THEN T = T - 256
260 GOTO 20
anim_4.gif
C++:
10 T = 0
' U и V — это динамические множители масштаба сетки
20 U = 16
30 V = 16

' --- 1. СЛУЧАЙНОЕ ИЗМЕНЕНИЕ МАСШТАБА (РАНДОМНАЯ ПРОГУЛКА) ---
' Кадрирование плавно "дышит", меняя размер пятен
100 R = RND 0 , 3
110 IF R == 0 THEN U = U + 1
120 IF R == 1 THEN U = U - 1
130 R = RND 0 , 3
140 IF R == 0 THEN V = V + 1
150 IF R == 1 THEN V = V - 1

' Ограничиваем масштаб, чтобы плазма не стала слишком мелкой или крупной
160 IF U < 8 THEN U = 8
170 IF U > 28 THEN U = 28
180 IF V < 8 THEN V = 8
190 IF V > 28 THEN V = 28

' --- 2. ОТРИСОВКА КАДРА ---
200 FOR I = 0 TO PIXEL
210   X = I % 16
220   Y = I / 16

' --- ЗМЕЙКА (ZIGZAG) ---
' Раскомментируй, если матрица спаяна зигзагом:
' 221 Z = Y % 2
' 222 IF Z == 1 THEN X = 15 - X

' Применяем "дышащий" масштаб к координатам
230   X = X * U
240   Y = Y * V

' ВОЛНА 1: Горизонтальная, но её изгибает координата Y (эффект водоворота)
250   M = Y + T
260   M = M % 256
270   M = SIN8 M
280   M = M / 3              ' M - это сила искажения (0-85)
290   A = X + T + M          ' Подмешиваем искажение в волну X
300   A = A % 256
310   H = SIN8 A

' ВОЛНА 2: Вертикальная, но её изгибает координата X
320   N = X + 256 - T
330   N = N % 256
340   N = COS8 N
350   N = N / 3
360   B = Y + 256 - T + N    ' Подмешиваем искажение в волну Y
370   B = B % 256
380   S = COS8 B
390   H = H + S

' ВОЛНА 3: Диагональная (добавляет асимметрии)
400   C = X + Y + T
410   C = C % 256
420   S = SIN8 C
430   H = H + S

' Усредняем и выводим
440   H = H / 3
450   SET_HSV I , H , 255 , 255
460 NEXT I

' --- 3. СДВИГ ВРЕМЕНИ ---
470 WAIT 30
480 T = T + 4
490 IF T > 255 THEN T = T - 256
500 GOTO 100
anim_8_1.gif
C++:
' 1. КООРДИНАТЫ 7 ЗВЕЗД КОВША (X и Y)
10 A = 2
11 B = 7

12 C = 5
13 D = 4

14 E = 8
15 F = 4

16 G = 11
17 H = 7

18 I = 10
19 J = 5

20 K = 14
21 L = 4

22 M = 14
23 N = 7


24 U = RND 0 , 255   ' Случайный стартовый цвет
25 T = 0             ' Таймер анимации

' --- 2. ГЛАВНЫЙ ЦИКЛ ---
100 CLEAR

' === СЛОЙ 1: ФОНОВЫЕ ЗВЕЗДЫ ===
' Перебираем все пиксели матрицы
110 FOR Z = 0 TO PIXEL
120   S = Z * 37
130   S = S % 256
' Если S > 15, пропускаем (оставляем мало звезд для фона)
140   IF S > 15 THEN GOTO 210

' Пульсация тусклых звезд
150   W = Z * 11 + T
160   W = W % 256
170   V = SIN8 W
180   V = V / 5                ' Делим на 5, чтобы они были еле видны
190   SET_HSV Z , 160 , 100 , V
200   GOTO 220
210   SET Z , 0 , 0 , 0
220 NEXT Z

' === СЛОЙ 2: БОЛЬШАЯ МЕДВЕДИЦА ===
' Плавно меняем цвет ковша
230 U = U + 1
240 IF U > 255 THEN U = U - 256

' Отрисовка 1 звезды (Алькаид)
250 X = A
260 Y = B
270 O = 0
280 GOSUB 1000

' Отрисовка 2 звезды (Мицар)
290 X = C
300 Y = D
310 O = 30
320 GOSUB 1000

' Отрисовка 3 звезды (Алиот)
330 X = E
340 Y = F
350 O = 60
360 GOSUB 1000

' Отрисовка 4 звезды (Мегрец)
370 X = G
380 Y = H
390 O = 90
400 GOSUB 1000

' Отрисовка 5 звезды (Фекда)
410 X = I
420 Y = J
430 O = 120
440 GOSUB 1000

' Отрисовка 6 звезды (Дубхе)
450 X = K
460 Y = L
470 O = 150
480 GOSUB 1000

' Отрисовка 7 звезды (Мерак)
490 X = M
500 Y = N
510 O = 180
520 GOSUB 1000

' --- ОБНОВЛЕНИЕ КАДРА ---
530 WAIT 30
540 T = T + 4
550 IF T > 255 THEN T = T - 256
560 GOTO 100


' --- 3. ПОДПРОГРАММА: РАСЧЕТ И ОТРИСОВКА ЗВЕЗДЫ ---
' На входе: X, Y - координаты, O - сдвиг мерцания
1000 P = Y * 16

' --- ЗМЕЙКА (ZIGZAG) ---
' Если матрица спаяна зигзагом, убери апострофы в двух строках ниже:
' 1010 Q = Y % 2
' 1020 IF Q == 1 THEN X = 15 - X

1030 P = P + X

' Расчет яркого мерцания
1040 W = T * 3 + O
1050 W = W % 256
1060 V = SIN8 W
1070 V = V / 2
1080 V = V + 128     ' +128 гарантирует, что ковш всегда яркий (от 128 до 255)

1090 SET_HSV P , U , 255 , V
1100 RETURN
UDP:
anim_8_1.gif
C++:
' --- АВТО-ОПРЕДЕЛЕНИЕ ШИРИНЫ МАТРИЦЫ (W) ---
1 W = 1
2 I = W * W
3 IF I > PIXEL THEN GOTO 10
4 W = W + 1
5 GOTO 2

' --- ИНИЦИАЛИЗАЦИЯ ПАРАМЕТРОВ ---
10 Q = W - 1           ' Максимальная координата
11 O = Q / 2           ' Центр матрицы (для 16x16 это 7)
12 N = 160 / W         ' Авто-масштаб силы закручивания спирали
13 T = 0               ' Время (угол поворота)

' --- ГЛАВНЫЙ ЦИКЛ ПО МАТРИЦЕ ---
20 FOR Y = 0 TO Q
30   FOR X = 0 TO Q

' 1. Находим смещение от центра
40     U = X - O
50     V = Y - O

' 2. Вычисляем примерное расстояние от центра
60     E = ABS U
70     F = ABS V
80     M = MAX E , F
90     B = MIN E , F
100    D = M + B / 2

' 3. Угол закручивания спирали с авто-масштабом N
110    A = D * N
120    A = T - A
130    A = A + 2560
140    A = A % 256

' 4. Синус и Косинус для матрицы поворота
150    S = SIN8 A
160    S = S - 128
170    C = COS8 A
180    C = C - 128

' 5. Вращаем координату X с помощью матрицы поворота
190    K = U * C
200    L = V * S
210    R = K - L

' 6. Превращаем закрученную координату в цвет радуги
220    H = R / 10
230    H = H + T
240    H = H + 2560
250    H = H % 256

' 7. Расчет индекса пикселя
260    P = Y * W + X

' РЕВЕРС ДЛЯ ЗИГЗАГ-МАТРИЦЫ (Универсальный)
270    ' Z = Y % 2
271    ' J = Q - X
280    ' IF Z == 1 THEN P = Y * W + J

' 8. Выводим яркий цвет
290    IF P <= PIXEL THEN SET_HSV P , H , 255 , 255

300  NEXT X
310 NEXT Y

' --- АНИМАЦИЯ ---
320 WAIT 30
330 T = T + 6          ' Увеличиваем угол вращения
340 IF T > 255 THEN T = T - 256
350 GOTO 20
anim_6.gif
C++:
' --- АВТО-ОПРЕДЕЛЕНИЕ ШИРИНЫ МАТРИЦЫ (W) ---
1 W = 1
2 I = W * W
3 IF I > PIXEL THEN GOTO 10
4 W = W + 1
5 GOTO 2

' --- ИНИЦИАЛИЗАЦИЯ ПАРАМЕТРОВ ---
10 Q = W - 1           ' Максимальная координата (замена числа 15)
11 K = W * 3 / 2       ' Авто-расчет времени жизни волны (замена числа 24)

' --- ИНИЦИАЛИЗАЦИЯ НОВОЙ КАПЛИ ---
12 A = RND 0 , Q       ' Случайный центр X
13 B = RND 0 , Q       ' Случайный центр Y
14 T = 0               ' Радиус круга (счетчик времени)

' --- ОТРИСОВКА КАДРА (ЦИКЛ ПО МАТРИЦЕ) ---
40 FOR Y = 0 TO Q
50   FOR X = 0 TO Q

' Вычисляем дистанцию от текущего пикселя (X,Y) до центра (A,B)
60     U = X - A
70     U = ABS U
80     V = Y - B
90     V = ABS V
100    M = MAX U , V
110    N = MIN U , V
120    D = M + N / 2      ' D - аппроксимированное расстояние (радиус)

' Насколько этот пиксель далек от текущей волны T?
' (Используем E вместо W, чтобы не стереть ширину матрицы)
130    E = D - T
140    E = ABS E

' Базовый цвет воды (темно-синий фон)
150    H = 160
160    S = 255
170    L = 20

' Если пиксель прямо на границе волны (E == 0) — рисуем белый/голубой гребень
180    IF E == 0 THEN H = 140
190    IF E == 0 THEN S = 100
200    IF E == 0 THEN L = 255

' Если пиксель чуть позади/спереди волны (E == 1) — делаем плавный спад яркости
210    IF E == 1 THEN L = 100

' Вычисляем 1D индекс для матрицы (зависит от W)
220    P = Y * W + X

' ЕСЛИ ВАША МАТРИЦА СПАЯНА ЗИГЗАГОМ (snake), РАСКОММЕНТИРУЙТЕ 3 СТРОКИ НИЖЕ:
230    ' R = Y % 2
235    ' J = Q - X
240    ' IF R == 1 THEN P = Y * W + J

' Отрисовка пикселя (защита от выхода за границы ленты PIXEL)
250    IF P <= PIXEL THEN SET_HSV P , H , S , L

260  NEXT X
270 NEXT Y

' --- АНИМАЦИЯ ---
280 WAIT 40           ' Выводим кадр и ждем 40мс
290 T = T + 1         ' Увеличиваем радиус

' Если круг ушел за пределы матрицы (T меньше лимита K), рисуем дальше
300 IF T < K THEN GOTO 40
' Иначе пускаем новую каплю!
310 GOTO 12
anim_7.gif
C++:
' --- АВТО-ОПРЕДЕЛЕНИЕ ШИРИНЫ МАТРИЦЫ (W) ---
1 W = 1
2 S = W * W
3 IF S > PIXEL THEN GOTO 10
4 W = W + 1
5 GOTO 2

' --- ИНИЦИАЛИЗАЦИЯ ПАРАМЕТРОВ ---
10 Q = W - 1           ' Максимальная координата (для 16х16 это 15)
11 A = Q / 2           ' Авто-центр матрицы по X
12 B = Q / 2           ' Авто-центр матрицы по Y
13 K = 352 / W         ' Авто-масштаб толщины волны (замена жесткому 22)
14 T = 0               ' Время (фаза сдвига)

' --- ОТРИСОВКА КАДРА (ЦИКЛ ПО МАТРИЦЕ) ---
20 FOR Y = 0 TO Q
30   FOR X = 0 TO Q

' Алгоритм дистанции без float (до центра A, B)
40     U = X - A
50     U = ABS U
60     V = Y - B
70     V = ABS V
80     M = MAX U , V
90     N = MIN U , V
100    D = M + N / 2

' Считаем фазу волны.
' 5000 добавлено (вместо 500), чтобы 100% избежать ухода в минус на больших матрицах
110    F = D * K
120    F = 5000 + T - F
130    F = F % 256        ' Закольцовываем в диапазон 0-255

' SIN8 плавно переведет фазу (0-255) в яркость (0-255)
140    L = SIN8 F

' Индекс пикселя (зависит от ширины W)
150    P = Y * W + X

' РЕВЕРС ДЛЯ ЗИГЗАГ-МАТРИЦЫ (Универсальный):
160    ' R = Y % 2
170    ' J = Q - X
180    ' IF R == 1 THEN P = Y * W + J

' Рисуем пиксель: H=150 (Водный синий), S=255 (насыщенный), L (волны синусоиды)
190    IF P <= PIXEL THEN SET_HSV P , 150 , 255 , L

200  NEXT X
210 NEXT Y

' --- АНИМАЦИЯ ---
220 WAIT 30           ' Отрисовать кадр
230 T = T + 12        ' Двигаем волну вперед (скорость)
240 IF T > 255 THEN T = T - 256
250 GOTO 20
 
Изменено:
  • Лойс +1
Реакции: veuz

VktrSansara

✩✩✩✩✩✩✩
1 Дек 2018
13
8
Новомосковск
Обновление.
  • Проделана большая работа по оптимизации Библиотеки:
    • HSV - как у FastLED.
    • Линковка адресов
    • Бинарный поиск
    • Указатели вместо индексов
    • Некоторые функции IRAM_ATTR inline ...
    • Скорость выросла на 20 - 30%
  • Новые функции BASIC:
    • MAP - управление диапазонами.
      MAP val , i_min , i_max , o_min , o_max
      H = MAP N , 0 , 255 , 85 , 200
    • CONSTRAIN - ограничение значений.
      CONSTRAIN val , lo , hi
      V = CONSTRAIN N , 0 , 255
    • EXP8 - гамма-коррекция (x^2.2), таблица 256 байт PROGMEM.
      EXP8 x
      V = EXP8 SIN8 T
    • NOISE - двумерный шум.
      NOISE x , t
      N = N * 3 + NOISE X, T * 3
  • LedBasic IDE:
    • Добавлены MAP, CONSTRAIN, EXP8, NOISE.
anim_8_1.gif
C++:
10 T = 0
20 FOR I = 0 TO PIXEL
30   X = I * 30
40   S = NOISE X , T
50   W = NOISE X * 3 , T * 4
60   V = S / 2 + W / 2
70   H = 140 + S / 8
80   SET_HSV I , H , 255 , V
90   IF V > 220 THEN SET I , 200 , 230 , 255
100 NEXT I
110 WAIT 25
120 T = T + 3
130 IF T > 255 THEN T = T - 256
140 GOTO 20
anim_8_1 (2).gif
C++:
10 T = 0
20 FOR I = 0 TO PIXEL
30   X = I * 25
40   N = NOISE X , T
50   U = X * 3
60   B = NOISE U , T * 2
70   U = X * 5
80   C = NOISE U , T * 3
90   V = N * 4 + B * 2 + C
100  V = V / 7
110  IF V >= 80 THEN GOTO 150
120  R = V * 2
130  SET I , R , 0 , 0
140  GOTO 210
150  IF V >= 160 THEN GOTO 170
160  G = V * 2 - 160
161  SET I , 255 , G , 0
162  GOTO 210
170  IF V >= 220 THEN GOTO 190
180  G = V + V / 2 - 80
181  SET I , 255 , G , 0
182  GOTO 210
190  G = 220
200  B = V - 220
201  B = B * 4
202  SET I , 255 , G , B
210 NEXT I
220 WAIT 30
230 T = T + 4
240 IF T > 32000 THEN T = 0
250 GOTO 20
anim_8_1.gif
C++:
10 T = 0
20 FOR I = 0 TO PIXEL
30   X = MAP I , 0 , PIXEL , 0 , 255
40   D = ABS X - 128
50   P = T - D
60   P = CONSTRAIN P , 0 , 255
70   A = SIN8 P
80   A = EXP8 A
90   P = T / 2 - D
100  P = CONSTRAIN P , 0 , 255
110  B = SIN8 P
120  B = EXP8 B
130  B = B / 3
140  V = CONSTRAIN A + B , 0 , 255
150  H = MAP V , 0 , 255 , 0 , 15
160  C = MAP V , 0 , 255 , 255 , 80
170  SET_HSV I , H , C , V
180 NEXT I
190 WAIT 18
200 T = T + 6
210 IF T > 900 THEN T = 0
220 GOTO 20
 
Изменено:
  • Лойс +1
Реакции: veuz