Таблица заранее вычисленных значений избавляет микроконтроллер от тригонометрии и возведения в степень во время работы: синус для генератора или кривую яркости достаточно один раз посчитать и записать во флеш-память.
Формулы
Синус на N точек за период для ЦАП или ШИМ (значения от 0 до max) и знаковый (от −A до A):
Гамма-коррекция и светлота CIE L* для диммирования:
где для CIE L* = 100 · i / (N − 1), а значение таблицы — max · Y.
Синус для генератора
Таблица синуса — основа прямого цифрового синтеза: на каждом прерывании таймера к фазовому аккумулятору прибавляют шаг, а старшие биты аккумулятора служат индексом в таблице. Чем больше точек и разрядность значений, тем меньше искажения, но тем больше памяти занимает таблица. Однополярная таблица подходит для ЦАП и ШИМ, знаковая — для цифровой обработки, где синус затем масштабируют и сдвигают. Как получить из ШИМ аналоговый сигнал и подобрать фильтр, — в калькуляторе ЦАП на ШИМ.
Яркость светодиодов
Таблица гаммы или CIE L* ставится между регулятором и регистром сравнения таймера: номер ступени яркости — индекс, значение из таблицы — заполнение ШИМ. Частоту и разрядность ШИМ подбирают в калькуляторе таймеров микроконтроллера: для плавной регулировки на малой яркости нужно 10 бит и больше.
Частые вопросы
Зачем нужна гамма-коррекция для светодиодов?
Светодиод светит пропорционально заполнению ШИМ, а глаз воспринимает яркость нелинейно: шаг от 1 до 2 % заполнения заметен гораздо сильнее, чем от 90 до 91 %. Без коррекции регулировка «проскакивает» тёмный диапазон и почти не меняется в светлом. Таблица гаммы переводит равномерные шаги регулятора в заполнение ШИМ по степенной кривой с показателем 2,2–2,8.
Чем таблица CIE L* отличается от гаммы?
CIE L* — стандартная шкала светлоты CIE 1976: в самой тёмной части она линейна, дальше — кубическая. Середина шкалы, L* = 50, соответствует 18,4 % яркости, а гамма 2,2 в середине даёт 21,8 %. На практике обе кривые дают плавное диммирование; CIE L* аккуратнее в самой тёмной части, где у степенной кривой значения прижимаются к нулю.
Почему в 8-битной таблице гаммы в начале одни нули?
При гамме 2,2 и 256 точках с максимумом 255 первые 15 значений, с 0-го по 14-е, после округления равны нулю: столько уровней яркости 8-битный ШИМ просто не различает. Для плавного свечения на малой яркости таблицу делают для 10–16-битного ШИМ — задайте максимум 1023 или 65535.
Где хранить таблицу на AVR?
Обычный const-массив на AVR копируется при старте в оперативную память, которой у ATmega328P всего 2 КБ. С атрибутом PROGMEM таблица остаётся во флеш-памяти, а читают её макросами pgm_read_byte или pgm_read_word из avr/pgmspace.h — калькулятор добавляет пример чтения. На Cortex-M с GCC const-массив и так попадает во флеш-память.
Источники
- CIE 15:2004. Colorimetry, 3rd edition — светлота L* шкалы CIE 1976 и её связь с относительной яркостью Y
- Bruce Lindbloom. Lab to XYZ — обратное преобразование: Y = ((L* + 16)/116)³ при L* > 8, иначе L*/κ, κ = 903,3
- avr-libc: Program Space Utilities (avr/pgmspace.h) — размещение констант во флеш-памяти AVR и чтение pgm_read_byte, pgm_read_word
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/lookup-table/" title="Генератор таблиц для микроконтроллера" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/lookup-table/">Генератор таблиц для микроконтроллера</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено . Нашли ошибку в расчёте? Напишите нам.