Macro shot of a red 3mm LED

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

Читателям моего блога известно, что я работаю над обновлённой версией «Precision Clock» (но не спешите радоваться, до релиза ещё не один месяц). Одна из доработок этих «точных часов» коснулась дисплея, который теперь отображает время с точностью до миллисекунды. Причём я переработал его в корне, чтобы убрать мерцание, возникающее при записи работы часов на скоростную камеру.

Насколько мне известно, в продаже нет готовых драйверов LED-дисплеев, которые бы соответствовали моей спецификации. Практически все современные драйверы имеют последовательную адресацию, и даже самые быстрые не превышают частоту обновления 50 МГц, чего для моих нужд маловато. Просто на рынке нет спроса на драйверы, которые бы обеспечивали обновление со скоростью вплоть до миллисекунд.

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

Closeup of the LDR on the Precision Clock
Крупный план фоторезистора в модели «Precision Clock»

Пожалуй, лучшей частью моих точных часов как раз является схема автоматической корректировки яркости. Это полностью аналоговый механизм, состоящий из всего нескольких компонентов. Но при этом он функционирует настолько чётко, что я даже не могу придумать, чтобы ещё улучшить. Он работает во всём динамическом диапазоне, начиная от яркого солнечного дня и заканчивая беспроглядной тьмой. Механизм мгновенно реагирует, но с некоторым сглаживанием из-за кривой ответа фоторезистора, и в нём нет ШИМ. При всём при этом он ещё и настраиваемый. Создание подобной схемы оказалось возможным, только благодаря принципу, по которому драйвер дисплея получает опорный ток.

Screenshot from the MAX7219 datasheet
Скриншот из спецификации к MAX7219

Так работает большинство драйверов дисплеев. Контакт (обычно обозначенный, как Iset) получает опорный ток. Этот ток передаётся, или отображается, в управляющие транзисторы каждого сегмента, где в результате умножения на коэффициент усиления транзистора определяет ток этих сегментов. Предполагаемое применение такой схемы заключается в использовании резистора, который будет определять опорный ток, и регулировке яркости дисплея посредством ШИМ. Естественно, я смог взять её за основу для создания собственной схемы регулировки яркости с использованием всего нескольких компонентов.

В случае дискретных компонентов резисторы стоят дёшево, а транзисторы дорого, но в интегральных схемах всё наоборот. Транзисторы для них совсем недорогие, а резисторы добавлять очень трудно, особенно, если вы хотите соблюсти жёсткие допуски. Если говорить о схеме, где требуется множество подтягивающих резисторов, то она традиционно реализуется в виде одного резистора для установки опорного тока, после чего этот ток везде отображается транзисторами. И когда резистор должен иметь конкретную характеристику (с допуском менее 50%), легче всего просто вывести его на отдельный контакт микросхемы, чтобы можно было подключать внешние компоненты, как в случае с драйверами дисплея.

Что у нас получается. Старая схема была прекрасна, но в новой модели она работать не будет. Тогда нужно придумать альтернативное решение, которое будет как минимум не хуже, а то и лучше.

Контекст

Для понимания этой статьи вам достаточно знать, что я использую микроконтроллер STM32 среднего сегмента (возможно, STM32L476).

Macro shot of an STM32L476 on a PCB
Макросъёмка STM32L476 на плате

Хорошенько всё обдумав, я принял решение управлять матрицей дисплея напрямую с контактов микроконтроллера. Используя прямой доступ памяти (DMA) микросхемы, можно настроить кольцевой буфер, который будет непрерывно отправлять сигналы на контакты ввода-вывода. Это позволит получить матрицу дисплея, не создавая на МК лишней нагрузки.

О прямом доступе к памяти

Прямой доступ к памяти позволяет копировать данные из одного места в другое. Этот механизм разработали, чтобы при необходимости перемещения данных процессор мог продолжать заниматься другими делами, не отвлекаясь. DMA не обязательно работает быстрее — по факту этот механизм даже медленнее, так как у процессора более высокий приоритет использования шин данных — но он сильно влияет на общую производительность компьютера.

Современные схемы DMA настолько сложны, что их порой очень трудно понять, но в случае STM32 всё не так страшно. В кольцевом режиме при достижении конца данных, происходит возврат к началу, так что здесь мы можем установить значения матрицы в памяти, и передавать их непрерывно на порт ввода-вывода. Матрица будет продолжать работать, и к данным потребуется обращаться только для обновления дисплея.

Контакты МК недостаточно мощны для управления всем дисплеем, напряжение которого при полной яркости может подниматься до 300 мА.

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

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

Регулировка яркости через напряжение получится нелинейной, но это можно компенсировать. Есть микросхемы, которые работают в диапазоне от 1,8 В до 3,6 В. С помощью такой можно достаточно легко управлять сегментами, используя вариацию напряжения от минимального до максимального.

Я могу обеспечить для этих буферных микросхем отдельный стабилизатор напряжения с возможностью корректировки, и тогда добавление в цикл обратной связи ещё одного резистора позволит мне управлять этим напряжением с помощью ЦАП основного микроконтроллера.

Прекрасно. Нужно лишь установить на плату датчик освещённости, соединить всё через DMA, и у нас получится дисплей с полностью автоматической регулировкой яркости.

Однако я же не просто хотел сделать альтернативу предыдущей модели, я хотел её улучшить. И одним из минусов старой схемы было то, что датчик освещённости находился с задней стороны часов. Это вроде и не особо важно, поскольку датчик всенаправленный, но разве не лучше, если он будет направлен вперёд?

Идея

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

У любого 7-сегментного дисплея есть десятичные точки, но большинство из них не используются.

Closeup of the front of the clock
Лицевая сторона дисплея крупным планом

Ни для кого не секрет, что в случае нужды светодиод можно использовать как датчик света. Можно ли тогда задействовать эти невостребованные десятичные точки для детекции освещённости?

Я подцепил мультиметр к одной из таких точек и посветил на дисплей фонарём — результат оказался многообещающим.

Multimeter connected to the pins of the display, reading 94.7mV
Мультиметр, подключённый к контактам дисплея, показания 94.7мВ

Однако подключение 7-сегментных дисплеев организовано через общий минус, что обычно очень удобно, но в данном случае затрудняет считывание уровня освещённости со свободной точки после включения дисплея. Использование матрицы означает, что катоды сегментов необходимо поочерёдно активировать, подтягивая то к нижнему, то к верхнему уровню. Можно реализовать подключение по принципу «открытый сток», тогда при отключении цифры будет возникать высокое сопротивление. Но выбранные мной буферные микросхемы являются двунаправленными.

Теперь поговорим о том, как измерять уровень освещённости с помощью светодиода. Для этого есть несколько способов. Простейший — это просто замерять напряжение разомкнутой цепи. Поступающий на датчик свет генерирует ток, число электронов в котором прямо пропорционально количеству поступившего света. P-N переход светодиода имеет ёмкость, и проходящий через него фототок ведёт к накоплению на конденсаторе заряда, пока не будет достигнуто равновесие с утечкой тока. 

Входное сопротивление мультиметра в 1 MΩ может значительно повлиять на напряжение. Более того, равновесное напряжение имеет очень нелинейную зависимость от интенсивности поступающего света.

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

Transimpedance amplifier with a reverse-biased LED
Трансимпедансный усилитель со светодиодом, подключённым с обратным смещением

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

Тем не менее в моём замысле с использованием десятичной точки эта ёмкость оказалась губительной. Я думал, мне удастся получать сигнал с трансимпедансного усилителя в подходящей части матрицы, чтобы напряжение смещения было согласованным для каждого показания. Но в итоге стало ясно, что на ожидаемых нами частотах дисплея это не сработает. Кроме того, рассеивающий материал, закрывающий точку, поглощает много света. Я надеялся, что можно будет это обойти, подключив все точки параллельно, чтобы усреднить их выходные сигналы, но это тоже увеличивает общую ёмкость.

Потратив на все эти эксперименты уйму времени, я решил, что нужно искать другой подход.

Идея получше

Первая идея не состоялась из-за рассеивающего слоя поверх точек и того факта, что все светодиоды подключены к остальной части высокоскоростной матрицы. Однако в часах есть и другие светодиоды, не перекрытые рассеивающим слоем и не требующие подключения к стандартной матрице. Я говорю о разделительных двоеточиях.

Illuminated colon separators of the clock
Разделительные двоеточия в часах

Отличие здесь в том, что эти светодиоды должны светиться, и это создаёт новую серию проблем. Хотя я уверен, что они вполне преодолимы.

Можно собрать для управления этими светодиодами кастомную плату, которая позволит регулировать их яркость посредством ШИМ. В моменты отключения ШИМ-сигнала я смогу измерять уровни освещения.

После нескольких доработок у меня получилась такая схема:

Schematic for the automatic LED
Схема подключения автоматического светодиода

Первый усилитель настроен как трансимпедансный, а второй этап служит просто для некоторого усиления сигнала. ШИМ-сигнал микроконтроллера работает с двумя состояниями и передаётся как на светодиод, так и на (ограниченную по току) базу NPN-транзистора. Когда сигнал ШИМ находится на высоком уровне, он обеспечивает ток для анода светодиода и также активирует транзистор, зажигая этот светодиод. Если же сигнал на низком уровне, транзистор отключён, и анод, по сути, оказывается близок к нулю.

В трансимпедансном усилителе есть один интересный момент. Дело в том, что неважно, как именно к нему подключён источник тока. Если вы не используете обратное смещение, а просто подключаете его к земле, то разворот светодиода приведёт к инвертированию выходного сигнала. Тем не менее, если операционные усилители (ОУ) питаются от одного источника, нужно быть осторожным. Естественно, низковольтный «rail-to-rail» операционник будет предпочтительней, так как генерация отрицательного напряжения создаёт дополнительную нагрузку. Если же усилитель не может выдавать отрицательное напряжение, нужно следить за тем, чтобы сигналы оставались положительными.

Two ways of wiring up a transimpedance amplifier
Два способа подключения трансимпедансного усилителя

В своей схеме я намеренно решил создавать положительный сигнал на промежуточном этапе, а также реализовал второй этап без инвертирования. Неинвертирующий входной сигнал первого усилителя подключён к нулю, но можно было подключить его к опорному напряжению где-нибудь между шинами питания, слегка повысив его надёжность.

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

Максимально доступная нам частота ШИМ ограничена ёмкостью. Когда сигнал оказывается на нуле, возбуждённый светодиод медленно затухает до значения, пропорционального окружающему освещению. По факту окружающему свету пропорциональны не только итоговая яркость, но и скорость затухания. По сути, нам не нужно ждать окончательного установления уровня сигнала — можно просто фиксировать его через фиксированные промежутки времени.

Вот этот эффект, снятый на слегка трясущуюся камеру:

Здесь частота ШИМ была 1 кГц. И хотя это намного медленнее скорости, с которой должен работать основной дисплей, для управления двоеточиями такой частоты вполне достаточно.

Значения параметров я выбрал путём долгих проб и ошибок. Кстати, я не уточнил динамический диапазон, с которым работаю. Здесь у меня где-то 16 экспозиционных ступеней (EV) между солнечной уличной сценой и ужином при свечах. То есть в первой сцене примерно в 32 000 раз больше света, чем во второй, иначе говоря, разница где-то в 45 дБ.

Один из вариантов расширить этот диапазон — применить логарифмическую кривую усиления с помощью второго ОУ. В случае наших низковольтных усилителей «rail-to-rail» это будет непросто, но необходимо, если мы хотим получить полный динамический диапазон. АЦП в микроконтроллере 10-битный, значит, логарифмическая кривая усиления преодолеет низкую битовую глубину. Но прежде, чем приступать к этой доработке, я решил оценить, можно ли реализовать её, не добавляя процессору излишней нагрузки.

Автоматизация

Испытываешь некую особую удовлетворённость, когда удаётся задействовать практически все возможности микроконтроллера. Зачастую микросхемы оснащены кучей всяких фич, из которых одновременно ты обычно используешь лишь часть. Но иногда подворачивается случай, где МК идеально подходит, и всю его периферию можно задействовать разом.

Микросхемы STM32 среднего уровня имеют огромное число каналов DMA, и к этому моменту я уже использовал почти все из них. Например, несколько каналов ушло на дисплей, так как для всей матрицы задействуются несколько портов ввода-вывода. Передача по USB и флэш-память QSPI используют DMA при необходимости. Особенно активно прямым доступом к памяти пользуется UART, так как в более продвинутых моделях STM32 есть механизм прерывания по «Character Match» (CMIE). Он позволяет активировать прерывание при завершении строки и сбрасывать DMA, чтобы считывать следующую строку. Процессор при этом задействуется, только когда поступают готовые для обработки данные. Вполне неплохо.

В моём случае ШИМ генерируется по таймеру. Нам нужно на определённой фазе волны ШИМ фиксировать напряжение АЦП. Затем это показание нужно передать в память. Собрав определённое число таких показаний, можно будет вычислить по ним среднее и отправить его на ЦАП.

Все каналы DMA довольно однозначны, и с каждым из них можно использовать только конкретные таймеры и периферию. Мне пришлось немного вмешаться в эту схему и освободить Timer 2, чтобы назначить его на генерацию ШИМ. У таймера есть несколько каналов, один из которых управляет скважностью ШИМ. Другой канал, хоть и тактируется и сбрасывается тем же таймером, устанавливается на другое значение сравнения. АЦП настроен на активацию при этом событии сравнения, а канал DMA отдельно настроен сбрасывать значения с АЦП в память. В прерываниях DMA можно усреднить показания и отправлять значения яркости на ЦАП.

Если частота ШИМ равна 1 кГц, и мы хотим усреднить сотню измерений, то яркость дисплея будет обновляться с частотой 10 Гц. Звучит вроде не сильно плохо, но по факту при изменении уровня освещения наблюдаются рывки. Вместо этого можно настроить ещё один таймер и канал DMA на отправку значений в ЦАП. В прерываниях на середине передачи и в её конце можно делать последние измерения, вычислять новое значение яркости и генерировать гладкую кривую значений для отправки в ЦАП. При необходимости можно усреднять целую секунду данных и делать прерывания только раз в секунду, что создаст совсем незаметную нагрузку. Получится очень плавный переход, хотя и с заметной задержкой.

Итак, моя эпопея с поиском правильной конфигурации завершилась. Мне удалось реализовать автоматический механизм корректировки яркости без нагрузки на процессор с определением уровней освещённости при помощи одного из светодиодов дисплея.

Macro shot of a 3mm LED
Макроснимок светодиода 3 мм

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

В STM32L476 даже в качестве периферии есть операционные усилители. Крайне удобно!

Заключение

Несмотря на всю продуманность и эффективность получившегося дизайна, я решил его не использовать.

Собрав прототип часов с этой схемой контроля яркости, я всё-таки счёл её недостаточно хорошей.

И дело не в динамическом диапазоне — его можно расширить. И не в чувствительности — она вполне приемлема. Проблема, из-за которой устройство получилось никчёмным, в однонаправленности светодиодов. Я даже счистил их макушки, но и без них конус видимости оказался очень узким. Это означает, что простой наклон часов вверх может привести к максимальному повышению яркости дисплея, а тень от вашего лица — к его максимальному затемнению. В предыдущей модели я использовал фоторезистор, а он всенаправленный, причём настолько, что даже махание перед ним рукой практически никак на него не влияет.

Один из вариантов исправить мою схему — это установить на заднюю стенку дополнительные светодиоды, направленные в разные стороны. Среднего по их показаниям должно быть достаточно. Но если уж добавлять датчики, то тогда надо брать сразу фотодиоды, а это сделает саму идею использования светодиодов для детекции освещённости бессмысленной.

Короче, поскольку я решил сделать так, чтобы каждый аспект обновлённых часов был не хуже, а то и лучше прежнего, новая модель будет завершена ещё не скоро. Зато, когда я её всё же закончу, это будут крутейшие настенные часы в мире! 

Комментарии (3)


  1. randomsimplenumber
    03.08.2025 10:47

    Сколько усилий. Для экономии на фототдатчике ценой в 5 центов?


    1. Astroscope
      03.08.2025 10:47

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


  1. TrykinSchultz
    03.08.2025 10:47

    Круто конечно. Но проще взять цифровой датчик и разместить его сверху или сбоку.