Очень плавное регулирование светодиодной ленты

Megawollt
Offline
Зарегистрирован: 06.12.2015

Если регулировать классическим способом 0-255, то на перых процентах лента светит уже достаточно ярко.

Пробовал ставить r-c фильтр на выходе контроллера. Результат уже лучше, но яркость меняется нелинейно.

Может у кого уже были похожие проекты

Alex_Ferrum
Offline
Зарегистрирован: 04.05.2015

Да, совершенно верно, регулировать светодиодную ленту нужно нелинейно примерно также, как громкость. Чем больше яркость ленты, тем большая мощность нужна для изменения на едницу яркости (под единицей яркости здесь следует понимать 1% для шкалы от 0 до 100%, где 0% - не горит вообще, 100% - горит на максимальной яркости, причем переход (неважно уменьшение или увеличение яркости) воспринимается глазом линейно). У меня был проект регулировки громкости там для получение шкалы от 0 до 100% использовалась нелинейная регулировка от 0 до 4000 (милливольт, но это не особенно важно).

Что могу порекомендовать:

1. Использовать не 8-ми разрядный, а 16-ти разрядный таймер-счетчик, при помощи которого можно создать шкалу для нелинейной регулировки (то есть глазом регулировка будет восприниматься линейно, а само регулирование будет нелинейное).

2. Попробовать использовать регулировочную характеристику резисторов регулировки громкости или соответствующего цифрового потенциометра CAT5116.

Araris
Offline
Зарегистрирован: 09.11.2012

У меня работает подобная штука - "искусственный рассвет" на WS2812 В общих чертах выглядит так :

// Переменные
float RGBbrightness = 0; // общий уровень яркости (от 0 до 255)
float RGBincrement; // шаг приращения яркости, у меня вычисляется как (float) 255 / (RGBsunriseDurationInMinutes * 60);
float RGBbrightnessCalculated;  
float RGBconstanta = (251 * log10(2))/(log10(255)); // Эту формулу не я придумал, нагуглил где-то. Число 251 подобрал любимым методом тыка.
// Да, я использую тут тип float и почти не стыжусь этого )))).
//
// Далее с некоторой периодичностью вызывается функция, управляющая светом.
//
// В функции мы вычисляем RGBbrightnessCalculated и пользуемся ей для руления нагрузкой.
RGBbrightnessCalculated = pow(2, (RGBbrightness / RGBconstanta)); // Эту формулу тоже не я придумал )))).
if ( RGBbrightnessCalculated > 255 ) { RGBbrightnessCalculated = 255; }
RGBbrightness = RGBbrightness + RGBincrement; 
if ( RGBbrightness > 255 ) { RGBbrightness = 255; }
 

 

Megawollt
Offline
Зарегистрирован: 06.12.2015

Спасибо, попробую. У меня задача примерно такая же, но нужно связать это с регулятором

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Вообще для человека наиболее естественным является логарифмический масштаб:

- звук по высоте человек однозначно воспринимает как логарифм частоты,

- звук по громкости человек однозначно воспринимает как логарифм звукового давления,

- интенсивность света воспринимается человеком как логарифм мощности излучения,

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

А при 256 градациях линейного масштаба в логарифмическом выходит всего 8 - маловато.

MagicianT
Offline
Зарегистрирован: 03.10.2015
Такие формулы нелинейного преобразования в Экселе хорошо подбирать, там и график посмотреть можно.
У меня такая получилась функция, с коэфициентами флотами значений сколько хочешь, но до значений аргумента 16 на выходе 0.
 Y = 0.003921569 * POWER( X, 2)
Megawollt
Offline
Зарегистрирован: 06.12.2015

Интересное решение. А что такое power? pow()?

std
Offline
Зарегистрирован: 05.01.2012
const byte loga[64]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,16,18,
   22,25,28,29,30,33,36,39,42,46,49,53,56,60,64,68,72,77,81,86,
   90,95,100,105,110,116,121,127,132,138,144,150,156,163,169,
   176,182,189,196,203,210,218,225,233,240,248,255};

Надеюсь смысл ясен. Минус способа: 8-разрядная ШИМ становится фактически 6-разрядной. Хотите плавнее - велкам в аппаратное решение на TLC5940NT, скажем; или есть какой-то ещё синтезатор ШИМ. У 5940 например разрядность 14, т. о. 0-4095 против 0-255.

Заставить ShiftPWM делать подобное не удастся (там верхний предел 255 максимум).

Logik
Offline
Зарегистрирован: 05.08.2014

Та причем тут все это? ТС правильно пишет " то на перых процентах лента светит уже достаточно". Даже при ШИМ 1/256 лента уже светит заметно из-за своей бешеной нелинейности, ну и  нелинейности глаза. И тут как не пересчитывай - пофиг всеравно значения между 0 и 1/256 нет. Тут 3 путя видно: ШИМ большей розрядности, аппаратно снижать ток в режиме малого свечения и переходить на програмный ШИМ  в режиме малого свечения. Все пути хреновые, но третий более симпатичен лично мне. Я с проблемой столкнулся, подумал и забил. Чего и вам желаю.

MagicianT
Offline
Зарегистрирован: 03.10.2015

Megawollt пишет:

Интересное решение. А что такое power? pow()?

Названия функций в Экселе и С++ действительно несколько разные, но догадаться легко.
 
andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Logik пишет:

Даже при ШИМ 1/256 лента уже светит заметно из-за своей бешеной нелинейности, ну и  нелинейности глаза.

Лента как раз линейная (в режиме ШИМ), нелинеен исключительно глаз.

Цитата:

И тут как не пересчитывай - пофиг всеравно значения между 0 и 1/256 нет. Тут 3 путя видно: ШИМ большей розрядности, аппаратно снижать ток в режиме малого свечения и переходить на програмный ШИМ  в режиме малого свечения. Все пути хреновые, но третий более симпатичен лично мне. Я с проблемой столкнулся, подумал и забил. Чего и вам желаю.

Да, программное решение я тоже делал (во всем диапазоне яркостей). Но это было с 3-цветной лентой. Для одноцветной, думаю, разумнее вчего разбить яркости на два диапазона и в нижнем просто включать в цепь последователдьно дополнительный резистор.

Megawollt
Offline
Зарегистрирован: 06.12.2015

Вопрос к std как к человеку, знакомому с dmx :)

Что это за решение на  TLC5940NT? Вообще реально ли сделать контроллер с dmx с более плавной регулировкой, чем у китайцев?

std
Offline
Зарегистрирован: 05.01.2012

Возможно на выходе. То есть, подключается 5940 и можно управлять 16 каналами от 0 до 4095.

Вход будет ограничен сериалом. То есть, если будут быстро крутить ручку - обновляется цифра в DMX массиве всё равно не быстрее чем 56 кбит/с. Настоящий, неардуинный DMX - 2 Мбит/с. Впринципе, легко обходится при помощи ArtNet (DMX over UDP).

Чтобы превзойти разрядность самого DMX-а, делается функция аппроксимации. Например, если в исходнике стоит уровень 1, на выходе должно быть 16 (256->4096). Не просто отнимаем/устанавливаем вход*16, а реально отнимаем по единице (но на шкале 4096, со скоростью в 16 раз большей скорости опроса шкалы 256), пока не станет 1*16=16. Увеличилось - прибавляем, ну в общем и так далее. Правда получается некоторое запаздывание (latency), но найти приемлемый баланс возможно.

UPD. Как подключать 5940

Megawollt
Offline
Зарегистрирован: 06.12.2015

А почему ардуинный DMX такой не скоростной?

std
Offline
Зарегистрирован: 05.01.2012

Потому что библиотеки для него (DMXSimple, DMXSerial) построены на основе Serial. Мне это точно неизвестно, мб есть способ сделать его обработку поживее. Но это под силу каким-то AVR-гуру, а я всю жизнь на библиотеках... так что не смогу.

Logik
Offline
Зарегистрирован: 05.08.2014

andriano пишет:

Лента как раз линейная (в режиме ШИМ).

Нигде она нелинейна. Учитывая снижение эффективности от нагрева на высоких токах, наличия внутренней емкости при импульсных токах и процессов дрейфа, накопления и рекомбинации носителей от неё линейности недобешся. Можете на фотык поснимать, он линейней глаза, и светимость на малом токе (коротком импульсе) явно выше.  

 

andriano пишет:

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

Проблемой будет обеспечить "гладкий" переход между диапазонами. И вероятно неразрешимой проблемой. От температуры будет "плавать", потому переход на програмный ШИМ перспективней. 

Megawollt
Offline
Зарегистрирован: 06.12.2015

Я пробовал просто вешать конденсатор на базе выходного транзистора. Да, помогает, но диапазон становится еще нелинейнее

mnashe
Offline
Зарегистрирован: 29.08.2016

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

1. Использование 16-битного ШИМ. В atmega328 таких вроде два (из шести), оба висят на одном 16-битном таймере. Правда, придётся программировать порты напрямую, поскольку в стандартной реализации ардуино эти аппаратные возможности незадействованы.
Вариант 1.1: использовать для ШИМ дополнительный мк с несколькими каналами 16-битного PWM или PSMC, например, pic16f1572 (там 3 канала).
Вариант 1.2: TLC5940 (правда, 12-битный ШИМ, а не 16-битный, но зато аж 16 каналов).
Плавная регулировка делается простым умножением/делением на константу (близкую к единице). Например, так:

void step_brightness(byte channel, byte slow, boolean increase) {
  word br=brightness[channel];
  if (increase) {
    set_brightness(channel,min((((br+(1<<slow)-1)<<slow)+br)>>slow,65535));
    return;
  }
  set_brightness(channel,((br<<slow)-br)>>slow);
}

(этот же способ годится для любого способа реализации).

Недостаток способа: требуются дополнительные микросхемы (или, если без них, только два канала и прямое программирование портов).

2. Использовать два аппаратных диапазона яркостей, переключая (через полевик) токозадающий резистор в драйвере светодиода (так я сделал в фонарике для палатки) или два рабочих напряжения (это ближе к теме — подходит для гирлянд). Если с помощью люксметра (или просто фоторезистора с ардуинкой) точно совместить границы диапазонов, то этим способом можно добиться превращением обычных ардуинных 8-битных ШИМ в 12-битные: на значениях ниже 16 переключаться на более тусклую цепочку, возвращаясь при этом к значению 255.

Если хочется, можно и 3 цепочки переключать, тогда будет 16 бит.
Недостатки способа: лишние выводы ардуино, лишние детали, морока с калибровкой.

3. Управлять не только коэффициентом заполнения, но и периодом.
Недостатки способа:
Требует прямого программирования портов.
Невозможно задействовать все каналы, поскольку число таймеров в ардуино меньше числа каналов ШИМ, а для такого способа каждому ШИМу нужен собственный таймер. Но, скажем, если нужен всего один канал (или если таймеров хватает, как, например, на pic16f1824, где есть три отдельных 8-битных таймера для ШИМ), то этот способ будет самым простым.
Несколько сложнее расчёты. Нужно, фактически, преобразовывать действительное число в близкую по значению обыкновенную дробь (в пределах разрешения ШИМ — 8 или 10, в зависимости от мк). Поэтому на pic я просто просчитал на компьютере таблицу (в виде пар числитель-знаменатель) для 16 соседних ступенек и внёс её в виде таблицы констант, а следующие группы по 16 ступенек вычислял на основе этих делением числителя или, если это уже невозможно без потерь, умножением знаменателя на 2. Довольно сложная вышла программа (правда, я писал её для pic12f675, где вообще нет аппаратного ШИМа, но и на аппаратном при расчёте выходит довольно много ветвлений), но я думаю, что на ардуино можно тупо вычислять, пользуясь ардуинными библиотеками для действительных чисел, скорости хватит.
Регулировка выходит весьма плавной даже на 8-битном ШИМе: разница между 1/256 и 2/256 огромна, а разница между 1/256 и 1/255 столь же незаметна для глаза, как и разница между 255/256 и 1. Разве что значений ниже 1/256 на 8-битном ШИМе таким способ не достичь, так что тут уже без программного ШИМа на самых нижних ступеньках не обойтись.

4. Использовать программный ШИМ на ступеньках ниже 16.

Megawollt
Offline
Зарегистрирован: 06.12.2015

А что дает функция в примере?

mnashe
Offline
Зарегистрирован: 29.08.2016

Megawollt пишет:
А что дает функция в примере?
Плавное изменение яркости.

Суть в том, что нужно умножать / делить коэффициент заполнения (или период) на константу, а не просто добавлять / вычитать. Иначе на глаз выглядит, что яркость очень быстро нарастает в начале и медленно — в конце.

Ну, а самый быстрый способ умножить / разделить на число, близкое к единице, работающий и на мк без машинной команды умножения / деления, — это прибавить / вычесть само число, сдвинутое вправо (чем сильнее сдвигать, тем медленнее меняется яркость).

Кстати, я недавно сделал очень плавную мигалку на PIC12F1572. Это, кажется, самый дешёвый из современных PIC (enhanced mid-range), я купил на aliexpress по $0.42. И в нём есть три 16-битных ШИМ, которые можно вывести на любые три из пяти выходов (можно переключать программно). Подключил RGB, белый и жёлтый, и меняю разные цвета по кругу, очень красиво выглядит (кажется, как будто световое пятно плавно растёт и уменьшается).

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

Изменение яркости делается в трёх вложенных циклах: внешний цикл меняет коэффициент заполнения вдвое, остальные два меняют период. Средний цикл вычисляет 1/557 (для уменьшения периода, то есть увеличения яркости) или 1/551 (для увеличения периода, то есть уменьшения яркости) и затем полученное число шесть раз (это внутренний цикл) вычитает / прибавляет к текущему значению периода. Таким образом за шесть ступеней значение меняется в 557/551 раз. Средний цикл повторяется до тех пор, пока период не уменьшится / увеличится ровно вдвое.

Такой неудобный (в том плане, что невозможно здесь обойтись простым сдвигом, приходится программно делить) коэффициент выбран потому, что он практически точно совпадает с ⁶⁴√2 ((557/551)⁶⁴≈2,0000008).

Для вычислений используется 24-битное целое число, из которого загружается в регистр периода 16 старших бит. Та же идея, что в функции для ардуино, показанной выше (там вычисляется 16-битное число, из которого берутся старшие 8 бит).

Загрузка значений в регистры и вычисление следующий происходит по прерыванию таймера, тело программы не делает ничего, кроме выбора цветов, включения «рассвета» и «заката» и ожидания его окончания. Можно туда добавить что-нибудь полезное, но я пока не придумал :)

Если кому-то нужна эта программа для PIC (на ассемблере), могу выложить.

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

andriano пишет:
А при 256 градациях линейного масштаба в логарифмическом выходит всего 8 - маловато.

А если яркостью управлять классическим ШИМ, но интервал смены яркости подогнать под логарифмический, т.е. дискретность задержки перед следующим шагом должна быть 0, 2, 4, 8, 16, 32, 64, 128, 256 и т.д.

По идее, тогда получается и шагов смены яркости не 8, а 64 или 128 или 255, и нарастание яркости уже близкое к ожидаемому линейному.

kraiv
Offline
Зарегистрирован: 02.12.2015

Araris пишет:

У меня работает подобная штука - "искусственный рассвет" на WS2812 В общих чертах выглядит так :

// Переменные
float RGBbrightness = 0; // общий уровень яркости (от 0 до 255)
float RGBincrement; // шаг приращения яркости, у меня вычисляется как (float) 255 / (RGBsunriseDurationInMinutes * 60);
float RGBbrightnessCalculated;  
float RGBconstanta = (251 * log10(2))/(log10(255)); // Эту формулу не я придумал, нагуглил где-то. Число 251 подобрал любимым методом тыка.
// Да, я использую тут тип float и почти не стыжусь этого )))).
//
// Далее с некоторой периодичностью вызывается функция, управляющая светом.
//
// В функции мы вычисляем RGBbrightnessCalculated и пользуемся ей для руления нагрузкой.
RGBbrightnessCalculated = pow(2, (RGBbrightness / RGBconstanta)); // Эту формулу тоже не я придумал )))).
if ( RGBbrightnessCalculated > 255 ) { RGBbrightnessCalculated = 255; }
RGBbrightness = RGBbrightness + RGBincrement; 
if ( RGBbrightness > 255 ) { RGBbrightness = 255; }
 

 

 

Очень интересно, на неделе попробую. А еще, "искуственный рассвет" не раскроете подробности? Делали только приращение яркости или цвет тоже меняли? Каким образом? Спектр как-то подбирали?

Farmatsevt
Farmatsevt аватар
Offline
Зарегистрирован: 27.09.2018

Здравствуйте. Можете, пожалуйста, если вам не трудно, скинуть полную версию кода для этого проекта?

novak
Offline
Зарегистрирован: 25.02.2017

Собираюсь регулировать яяркость дисплея. Как думаете 8-уровней яркости будет достаточно? 

Собираюсь просто сдвигать 1 из младшего разряда к старшему либо со сдвигом выролнять запонение.

00000001   0x01
00000011   0x03
00000111   0x07
00001111   0x0F
00011111   0x1F
00111111   0x3F
01111111   0x7F
11111111   0xFF

ряд будет следующий 0, 1, 3, 7, 15, 31, 63, 127, 255

Tomasina
Tomasina аватар
Offline
Зарегистрирован: 09.03.2013

Плохой ряд. В диапазоне 0-30 яркость визуально мало меняется, а в диапазоне 60-140 смена яркости наиболее заметна (т.е. именно этот участок надо разбить на максимальное количество градаций).

mnashe
Offline
Зарегистрирован: 29.08.2016

Tomasina пишет:

Плохой ряд. В диапазоне 0-30 яркость визуально мало меняется, а в диапазоне 60-140 смена яркости наиболее заметна (т.е. именно этот участок надо разбить на максимальное количество градаций).

:o

Никогда  в жизни такого не видел. Во всех светодиодных светильниках визуальное восприятие яркости менялось вполне предсказуемо по логарифмической шкале (то есть для любых двух уровней яркости a и b визуальная разница между a и k⋅a та же, что между b и k⋅b).

dimax
dimax аватар
Offline
Зарегистрирован: 25.12.2013

novak пишет:

 Как думаете 8-уровней яркости будет достаточно? 

Достаточно ли класть одну чайную ложку сахара в стакан чая? :) -Дело вкуса.

Почему вам просто не попробовать, и решить хватает ли вам 8 уровней?