Использование цветовых пространств в ATTiny13a для WS2811
Моя новая идея посвящена использованию цветовых пространств в микроконтроллерах.То что моя новость кому-то таковой не покажется, я нисколько не удивлюсь.Однако я предлагаю метод и его реализацию, подобных которому я не встречал.Немного вступления, с чего все началось. Совсем недавно закончился год и в наследство от него у меня осталось около 300 светодиодов ws2811. Почему-то руки до них так и не доходили, но после празднования нового года у родственников я заметил, что у тётки стояла маленькая сувенирная ёлочка из стекла, которую она очень любит. Но она в этот раз совсем не сверкала и не искрилась по весьма банальной причине… сели батарейки. Вспомнив про свой набор светодиодов, пообещал сделать маленькую гирлянду для этой ёлочки, чтобы устранить эти недостатки раз и навсегда и сделать еще одного близкого мне человека хоть немного счастливее.Разработка вертится в голове, постепенно ускоряясь, иногда превращаясь в вихрь мыслей, но до этих дней с места так и не сдвинулась. Останавливало то, что все те идеи, которые касались программы эффектов и их переключений, выглядели в голове очень громоздкими и страшно неудобными, при реализации их в цветовом пространстве RGB, к тому же я никак не мог из-за этого определиться, какой контроллер использовать. Но благодаря моему небольшому опыту работы дизайнером, я имею знания и о других пространствах, что натолкнуло меня на мысли о HSL и HSV. Изобретать новое смысла не было, реализаций полно нужно, лишь поискать…, но я так и не нашел. Нет, я конечно нашел много интересных решений, и многие из них были Вашими, представленными прямо здесь, на Хабре, и за что я всем Вам бесконечно благодарен, Вы дали пищу для ума.
В итоге было решено остановиться на HSL, исключив из него одну компоненту S (Saturation), оставив ее константной (так как в реализации ЦДУ, этот параметр лишний), а контроллер решил использовать ATMega8U.
Набросав код и испытав прошивку, я понял что чего-то не хватает. И не хватило мне маленького несоответствия реалу.Каждый охотник желает знать… И вновь я возвращаюсь к этому вопросу, и вновь осознаю, что нет его…Нет оранжевого цвета в природе, как ни крути, он всего лишь оттенок.
Это и стало корнем и стержнем моей идеи, благодаря чему я полностью переписал код и придумал метод использования компактного описания цветового пространства, причем это уже совсем не HSL, HSV и не RGB, потому что я расширил диапазон оранжевого и вынес его в отдельный пространственный сектор.
Пространство можно представить как поверхность цилиндра в случае если оно замкнуто, с расположенными в углах, смещенными на 60 градусов базовыми цветами, между которыми заполнено градиентными переходами от одного базового цвета к другому:
Где высота цилиндра — это яркость, которая так же является составляющей градиента оттенков.То же самое пространство представляет прямоугольник со сторонами «A x B», где «А» это угол определяющий базовый цвет и его оттенок, а «B» — яркость, в случае если пространство не замкнуто или развернуто из цилиндра.
Для поставленной задачи я решил использовать квадрат со стороной 255×255, тем самым уложившись в тип байт, где для угла, значения изменяются в пределах 0…255 (байт), а яркость: -127…127 (знаковый байт), благодаря этому получил возможность использования 8-ми базовых цветов и 32 градаций оттенков для каждого.
Пространство описывается как массив с RGB — компонентами базовых цветов, а градиенты оттенков рассчитываются на лету.Пример описания:
{0,128,0}, {64,128,0}, {128,128,0}, {128,0,0}, {128,0,128}, {0,0,128}, {0,128,128}, {0,128,0} здесь описана последовательность базовых цветов, назовем ее просто — радуга, где порядок компонент изменен согласно даташиту ws2811 (GRB), а последний — красный цвет, служит для замыкания пространства, выглядит это так:
Теперь, если взять некоторый индекс цвета, например 183, то можно сделать его отражение в пространство RGB таким образом: Индекс базового цвета = 183 / 32 = 5 (синий, или {0,0,128})Смещение оттенка = 183% 32 = 23Теперь вычисляем разницу между компонентами полученного базового цвета ({0,0,128}) и следующего за ним {0,128,128}, чтобы вычислить приращение (назовем его дельтой):
dG = 0 — 0 = 0, dR = 128 — 0 = 128, dB = 128 — 128 = 0; Так как между цветами 32 градации, необходимо выполнить разбиение разности компонент: dG= 0 / 32 = 0, dR= 128 / 32 = 4, dB= 0 / 32 = 0; Теперь необходимо полученную дельту домножить на смещение оттенка и прибавить к компонентам текущего базового цвета ({0,0,128}): G = 0 + 0×23 = 0, R = 0 + 4×23 = 92, B = 128 + 0×23 = 128; Получили {0,92,128}, к которому теперь можно прибавить яркость, например 50: {50,142,178} — искомый цвет.Как видно из примера, ничего сложного нет. В случае если дельта принимает отрицательное значение, то смещение оттенка при умножении даёт отрицательное дополнение, которое в сумме даст разность с конечной компонентой, это произойдет в случае, когда компонента градиента идет на спад.
И да, яркость применяется не пропорционально, а линейно, что дает некоторую погрешность, но в рамках описанной задачи это не страшно. Так же необходимо следить за нижним порогом чтобы не вызвать переполнение при отрицательной яркости.
Таким образом полученное пространство дает возможность использования 255×255 = 65535 оттенков.
Весь описанный метод был оптимизирован, устранены все умножения и деления, и приведен под упрощенную быструю математику, позволяет легко переписать его на ассемблер (лично меня скорость абсолютно устраивает: 200 ns между расчетами компонент для 7-и светодиодов), если нужна оптимизация для уменьшения размера кода.В результате, первоначальное решение об использовании ATMega8u было отменено в пользу тиньки, так как полученная прошивка заняла меньше половины килобайта.
Нет, я не жлоб, я просто ленивый.
Итак, код ниже, выполняет инициализации, и содержит функцию вывода данных на линию ws2811:
А это код основного цикла и функция преобразования индекса пространства в цветовые составляющие с примером использования:
А вот видео с демонстрацией работы (правда цвета далеки от реальности):[embedded content]
Описывать подробней комментариев в тексте смысла нет, сам метод уже описан выше. Если есть вопросы, задавайте.
Ну вот, собственно, и все, что я хотел рассказать.
Давайте теперь на секунду представим, как можно использовать данный метод. Как вам, например, такое пространство, которое показано на этой картинке:
Правильно! Можно описывать разные цвета и градиенты между ними. И кто вначале описания решил что метод не позволяет использовать оттенки серого — не прав.
Массив, описывающий в памяти пространство, занимает 32 байта (из-за выравнивания), который хранится в программной памяти. Если создать несколько таких описаний пространств, и переключаться между ними на ходу, переключая указатель на массив, то можно выбирать текущее пространство для каждого нового светодиода в очереди, а так же позволяет расширить число градаций между оттенками. И если слегка модифицировать код, и увеличить число ступеней в описании компонент до 8-ми, то 32×8 даст 256 (в моем коде 3 ступени), то использование семи массивов (0…255 красный, желтый, зеленый, голубой, синий, фиолетовый, белый) дают комбинацию в 16m оттенков «одновременно на экране»! При использовании 224 байт прошивки для хранения. А если еще немного по-потеть и чуть переписать код, то можно уложиться и в 96 байт с тем же результатом.Плюс, благодаря оптимизации и полученной скорости обработки, можно использовать так называемый метод дизеринга ((англ. dither от старо-английского didderen — дрожать) С помощью чего, можно добиться еще большего числа оттенков. Так же это позволяет создавать замыкания пространств друг на друга, чтобы устранить или сделать невидимыми эффекты перехода. В общем, все предложенное может быть модифицировано как Вашей душе угодно, на Ваш вкус и цвет, а может использоваться как есть, и удовольствие я Вам гарантирую!
Вот теперь я вновь с вами прощаюсь, а вам оставляю исходный код в безвозмездное пользование.С нетерпением жду ваших комментариев, критики, вопросов и советов.Спасибо за внимание, до новых встреч!
Использование в коммерческих проектах, перепродажа исходного кода, использование с целью наживы и любых корыстных целях, запрещено. Исходные тексты распространяются бесплатно как есть, в случае использования на других сайтах, либо в других источниках, указание автора и уведомление о размещении — обязательно.