Управление яркостью подсветки дисплея Nextion в FLProg. IPhone X: отключаем мерцание OLED дисплея Отключение ШИМ тремя кликами

В настоящее время я занимаюсь проектом на Arduino с использованием TFT дисплея. Недавно мне захотелось добавить в него, казалось бы, простую функцию - функцию регулировки яркости. Нашёл в документации к библиотеке для работы с TFT дисплеем (UTFT Library) нужный метод: setBrightness(br);

Что нам понадобится?

  • В качестве основы, я использовал Frearduino ADK v.2.2 на базе процессора ATmega2560
  • TFT LCD Mega Shield v.2.2
  • Сам дисплей - 7" TFT LCD SSD1963 ()
  • UTFT Library - универсальная библиотека для работы с TFT дисплеями (Найти саму библиотеку, а так же документацию можно )
  • Паяльник

Разберёмся с железом

Открыв схему дисплея, можно увидеть, что на конвертер mp3032 идет три входа: LED-A, PWM, 5V. Изначально, PWM неактивен. Этот вход не используется совсем. Подсветка управляется LED-A.


Если взглянуть на обратную сторону дисплея, можно найти область, подписанную как "Backlight control" . Здесь то мы и найдём эти самые входы. Для управления подсветкой методом ШИМ, необходимо сделать так, чтобы все было наоборот: LED-A - неактивен, PWM - активен. Для этого придётся перепаять перемычку. Вот фото того, что должно получиться:

Программная часть

Так как наша библиотека не может дать то, что нам надо, мы сами напишем нужную функцию. Для этого откроем документацию к контроллеру, управляющему дисплеем (SSD1963). Управление SSD1963 осуществляется с помощью специальных команд, которые передаются с Arduino через специальные выходы, которые описаны в документации:

Управление осуществляется следующим образом: Arduino выводит через RS (D/C в таблице) 0, если мы собираемся передавать команду, 1 - если данные. После передачи команды, RS переключается на 1, и далее передаются необходимые параметры. Все команды и параметры передаются через выходы D0-D7. Если у вас ATmega2560, то все эти восемь выходов объединены в порт C.

Итак, для начала, напишем функцию передачи данных по шине. Для удобства использования, я буду писать прямо в UTFT.h:

Void Lcd_Writ_Bus(uint8_t bla) { digitalWrite(WR,LOW); //Настраиваем SSD1963 на чтение digitalWrite(CS, LOW); PORTC = bla; //Передаем на шину данные в виде одного байта digitalWrite(CS,HIGH); digitalWrite(WR,HIGH); }

Также стоит обратить внимание на названия методов, так как в библиотеке уже могут встретиться функции с такими же именами.
Добавим две функции для вывода команд и данных:

Void Lcd_Write_Com(uint8_t data) { digitalWrite(RS,LOW); //Переключаем RS в режим чтения команды, то есть 0 Lcd_Writ_Bus(data); } void Lcd_Write_Data(uint8_t data) { digitalWrite(RS,HIGH); //Переключаем RS в режим чтения данных, то есть 1 Lcd_Writ_Bus(data); }

Теперь сама настройка подсветки. Чтобы узнать, как осуществить все это, открываем документацию и ищем команду для настройки PWM.

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

Итак, вот, что нам надо:

То есть, сначала мы должны передать команду «0xBE», а потом, в качестве 3-х параметров передать частоту сигнала, длительность рабочего цикла, а также третий параметр, который определяет, включен DBC или нет (0x01 - выключен, 0x09 - включен).

Для регулировки самой яркости, необходимо изменять лишь частоту рабочего цикла. Так как мы передаём данные в виде одного байта, то значения цикла могут быть от 0 до 255. Я решил определить 9 уровней яркости (от 0 до 8). Следовательно, все 256 значений нужно разбить на 9 ступеней. Но также стоит обратить внимание на то, что если ступени будут равными, то яркость будет изменяться не так плавно, как хотелось бы. То есть уже, к примеру, на 4-ой ступени, яркость будет почти максимальной, а с 4-ой по 8-ую ступень будет изменять почти незаметно. Учитывая это, я решил использовать геометрическую прогрессию со знаменателем 2. То есть яркость будет вычисляться по следующей формуле: (2 ^ lvl) - 1 , где lvl - уровень яркости от 0 до 8. Обратите внимание, что так как значения начинаются с нуля, то необходимо вычесть единицу. Конечно, вы можете выбрать ступени и их значения сами, но я привёл вот такой, довольно просто пример. Теперь сам код:

Void setBright(byte lvl) { byte brightness(1); for (byte i(1); i <= lvl; i++) //Возведение в степень brightness *= 2; Lcd_Write_Com(0xBE); //Вывод команды Lcd_Write_Data(0x01); //Ставим частоту 760Гц Lcd_Write_Data(brightness-1); //Выводим длину рабочего цикла Lcd_Write_Data(0x01); //Отключаем DBC }

Теперь можно использовать UTFT.setBright(byte lvl);


В iPhone X компания Apple впервые использовала дисплейную панель, основанную на технологии органических светодиодов. И если достоинства OLED дисплеев очевидны, то об их недостатках пишут достаточно редко. Один из таких недостатков – мерцание экрана на низких уровнях яркости вследствие использования широтно-импульсной модуляции для управления свечением светодиодов на низких уровнях яркости. На языке обычного пользователя – в темноте экран мерцает.

Производители выбирают частоту мерцания экрана таким образом, чтобы большинство пользователей её не замечало. Чаще всего используется частота 240 Гц. Даже если отбросить значительную группу людей, которые замечают такое мерцание, остаются те, кто мерцания не замечает, но испытывает повышенную утомляемость, слезотечение, воспаление и покраснение глаз и даже мигрени. Таких людей не так уж мало: в зависимости от исследования и используемой методологии, их число составляет от 20 до 30% всех пользователей.

В устройствах под управлением Android проблему мерцания OLED-дисплеев часто можно решить установкой приложения, отображающего затемняющий фильтр; можно даже сохранить автоматическое управление яркостью, если для этого использовать приложение Lux Dash (о том, как его правильно настроить для отключения мерцания экранов, мы напишем в одной из следующих статей).

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

Почему OLED мерцают: управление яркостью посредством ШИМ

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

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

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

OLED без мерцания: миф или реальность?

Можно ли собрать OLED экран без мерцания? Да, такое вполне возможно, но на практике используется нечасто. Одним из немногих примеров таких экранов является матрица P-OLED, которую устанавливали в смартфоны LG G Flex 2. Обратной стороной таких экранов были вот такие эффекты, проявляющиеся на минимальной яркости:

Ошибкой было бы полагать, что LG сделали матрицу настолько хуже конкурентов. Матрицы Samsung в те времена обладали похожим качеством – с одним крупным отличием. OLED панели, которые Samsung устанавливает во все свои флагманы, мерцают на всех уровнях яркости – даже на 100%. Почему же изображение на мерцающей матрице выглядит настолько чище, чем на OLED без мерцания?

Эффект связан с разбросом параметров между соседними светодиодами. Разброс присутствует на матрицах всех производителей, но проявляется он в большей степени тогда, когда на светодиоды подаётся низкое напряжение. Эффект чем-то похож на цифровые шумы при фотографировании в тёмных условиях с короткой выдержкой. Чем меньше фотонов попадает на светочувствительные элементы матрицы – и чем меньше фотонов излучается диодом OLED – тем больше вероятность возникновения погрешности, «цифрового шума наоборот».

В Samsung решили проблему, всегда подавая на светодиоды максимальное напряжение и регулируя яркость при помощи скважности импульсов. Но постоянное мерцание экрана по вкусу далеко не всем, и ряд производителей остановились на гибридном подходе: до некоторого значения яркость регулируется уменьшением напряжения светодиодов; после пересечения заданного минимального уровня (обычно 15-50%) дальнейшее понижение яркости достигается при помощи ШИМ.

Если говорить конкретно про iPhone X, то яркость в нём регулируется так (по данным iXBT):

До уровня 50% мерцания нет; дальнейшее снижение яркости достигается мерцанием на частоте 240 Гц. Убедительно продемонстрировали это немецкие обозреватели с сайта Notebookcheck.net:

Как проверить мерцание экрана

Мерцает ли экран вашего телефона? Даже если ваши глаза не замечают никакого мерцания, его наличие или отсутствие легко проверить дома без какого-либо специального оборудования. Достаточно открыть на смартфоне страницу с белым фоном (например, about:blank в браузере Safari или Chrome), поместить телефон в тёмную комнату, снизить яркость до минимума и навести на экран камеру другого смартфона. Если мы видим что-то похожее на показанное в видеоролике ниже, мерцание экрана присутствует:

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

Экспериментально установлено, что у iPhone X минимальный уровень яркости без мерцания – 50%. Но если держать яркость на этом уровне, то в тёмных условиях устройством будет пользоваться некомфортно. Задача – понизить эффективный уровень яркости экрана, но не допустить мерцания.

Как оказалось, это вполне возможно. Для этого в настройках iOS предусмотрен специальный режим, который можно найти в настройках Accessibility > Display Accomodations.

В этом режиме экран затемняется программным фильтром. Чтобы включить этот режим, нужно зайти в Display Accomodations и активировать ползунок. Теперь нужно нажать на надпись Display Accomodations и активировать ползунок Reduce White Point (см. скриншот). Попробуйте начать со значения в промежутке от 85 до 100% и настройте до комфортного для ваших глаз уровня (яркость экрана в центре управления должна быть на уровне 50%).

Отключение ШИМ тремя кликами

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

На iPhone X включение и отключение фильтра можно реализовать по трёхкратному нажатию на боковую кнопку, в прошлых поколениях устройств выполняющую функции включения и выключения телефона. Для этого нужно найти в настройках опцию Accessibility Shortcut и назначить на неё включение и отключение функции Reduce White Point (см. скриншоты).

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

Дополнительная информация

Пояснения к схеме

R2 – переменный резистор номиналом 10К. Центральный вывод резистора через НЧ-фильтр подключен к нулевому каналу АЦП. Напряжение на резисторе преобразуется в цифровой код, который записывается в регистр сравнения таймера Т0. Таким образом с помощью резистора осуществляется регулировка скважности ШИМ сигнала.

Led1 – мощный светодиод белого цвета. Падение напряжения на нем около 4 Вольт. Максимальный ток светодиода, задается резистором R5 и равен 100 мА.

(Uпит – Uled)/R5 = (5 - 4)/10 = 100 мА

IRLU024N – N–канальный полевой транзистор. Вместо него можно использовать любые полевые транзисторы серии IRL (L - это значит, что управляются логическим уровнем)

R3 – токоограничительный резистор на всякий случай. R4 – pull-down резистор. Затвор полевого транзистора нельзя оставлять "болтающимся в воздухе".

Программа

//************************************************************
// Учебный курс. Программирование микроконтроллеров AVR на Си
// Управление нагрузкой с помощью
// широтно-импульсной модуляции (ШИМ, PWM)

#include
#include

int main(void )
{
//инициализация портов
PORTB = 0;
DDRB = 0xff;

//инициализация таймера Т0
TIMSK = 0;
//реж. - fast pwm, вывод OC0 - неинверт. шим, clk/64
TCCR0 = (1< TCNT0 = 0;
OCR0 = 0;

//инициализируем АЦП
//ион - напряжение питания, выравнивание влево, нулевой канал

ADMUX = (0< //вкл. ацп, реж. непрерывн. преобр., разр. прерывания, частота преобр. = FCPU/128
ADCSRA = (1< //режим непрерывного преобразования
SFIOR = 0;

__enable_interrupt ();
while (1);
return 0;
}

//********************************
//прерывание АЦП
#pragma vector=ADC_vect
__interrupt void adc_my(void )
{

//считываем старший регистр АЦП и

//записываем в регистр сравнения

Пояснения к коду

Логика работы

Инициализация периферии - таймера Т0, модуля АЦП. Разрешение прерываний. Бесконечный цикл. В прерывании АЦП напряжение считанное с переменного резистора записывается в регистр сравнения OCR0. В микроконтроллере AVR для этого регистра организован буфер, и на самом деле запись происходит сначала в него. Из буфера же значение переписывается в OCR0, только когда происходит переполнение счетного регистра TCNT0. Параллельно циклу while и модулю АЦП, работает таймер Т0 и генерит на выводе OC0(PB2) ШИМ сигнал. Когда счетный регистр TCNT0 переполняется OC0 устанавливается в 1, когда значение счетного регистра совпадает с регистром сравнения OCR0, вывод устанавливается в 0.

Инициализация таймера

Прерывания таймера не используются, поэтому регистр TIMSK = 0.

За установки таймера Т0 отвечает конфигурационный регистр TCCR0.

Биты WGM01, WHM00 определяют режим работы. 11 - режим Fast PWM.

Биты CS02, CS01, CS00 - устанавливают коэффициент предделителя таймера. 011 - соответствует предделителю 64. Тактовая частота таймера/счетчика будет Fcpu/64

Биты COM01, COM00 -определяют поведение вывода OC0. 10 - соответствует неинвертированному ШИМ сигналу. 1 - при переполнении TCNT0, 0 - при совпадении TCNT0 c OCR0.

Инициализация АЦП

Пример №2. Генерация синусоидального сигнала с помощью ШИМ

Пояснение к схемe

Резистор R2 просто забыл выкинуть из схемы. R3 и C8 интегратор.

Программа

//************************************************************

// Генерация синуса с помощью

// широтно-импульсной модуляции (ШИМ, PWM)

//************************************************************

#include
#include
#include "TableSin.h"

int main(void )
{
//инициализация портов
PORTB = 0;
DDRB = 0xff;

//инициализация таймера Т0
TIMSK = (1< //реж. - fast pwm, вывод OC0 - неинверт. шим, предделитель - на 8
TCCR0 = (1< //обнуляем счетный регистр и регистр сравнения
TCNT0 = 0;
OCR0 = 0;

__enable_interrupt ();
while (1);
return 0;
}

//**********************************************************

//Прерывание таймера/счетчика Т0

#pragma vector = TIMER0_COMP_vect

__interrupt void Timer0CompVect(void )

Дисплей Nextion: http://ali.pub/1xz0e2

Я покупал такой: http://ali.ski/zF01b

Для начала добавим блок получения данных с дисплея Nextion. Он называется Nextion Get Attr .

Находится данный блок в программе FLProg: Панель Nextion HMI -> Элементы -> Получить Параметр

Настройка данного блока выглядит следующим образом:

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

Ну и создадим элемент Ползунок (Slider) , пропишем ему его имя в панели Nextion и id.

Параметр, выберем (val) и выберем период опроса каждую секунду.

Все на этом настройка блока получения параметров закончена.

Настройка данного блока выглядит вот так:

Главное в этом блоке выбрать раннее созданную панель Nextion и заменить константу, на вход.

После этого нужно добавить блок Number Change который находится Базовые элементы -> Детектор изменения числа

И все это соединить по такой схеме:

После чего загрузить все в Ардуино и наслаждаться изменением яркости нашего дисплея.

Нагляднее в Видео: