Одной из важнейших тем при разработке даже самых простых устройств, является тема вывода информации о текущем состоянии устройства.
Даже если устройство всё из себя вумное и подключено в глобальную сеть Интернет и у пользователя есть возможность видеть состояние этого устройства на модненьком смартфоне - всё равно остаются ситуации, когда нет альтернативы местной индикации состояния устройства. Примеры таких ситуаций привести не сложно.
Самый простой случай - когда связь устройства с интернетом пропала. Но знать о том, включен или выключен, например, нагреватель и до какой температуры нагрелось то, что он нагревает - пользователь всё равно хочет.
Или, другой вариант - о состоянии устройства желает знать человек, у которого нет под рукой смартфона с доступом к этому устройству.
Я уж не говорю о том случае, когда вывод какой-либо информации является прямой функцией устройства - часов, термометра, метеостанции, термостата и так далее.
Да и фактор человеческой лени... Просто глянув на устройство хочется сразу знать о его "жизни" - включено реле или нет, есть у него связь с сетью или нет, какую величину, намерял датчик.. И каждый раз лезть за смартфоном - лень.
ShIoTiny5 не является исключением - пользователь, пусть даже и самодельщик, хочет видеть удобное и красивое отображение состояния устройства.
Возможности ShIoTiny5 по отображению информации не так уж и велики.
Во-первых, это классическое подключение светодиода к ножке контроллера. Очень просто, но крайне неудобно. У модуля ESP8266 совсем немного ножек, поэтому, как только в устройстве собираются несколько реле или датчиков - ножек быстро перестаёт хватать.
Во-вторых - это передача информации через интернет на смартфон или ПК. Возможности для отображения информации тут безграничны. Но.. Не будешь же постоянно бегать со смартфоном по дому или даче. Вот оно устройство. Рядом. Хочется взглянув на него сразу видеть - живёт оно или померло. И, желательно видеть, насколько хорошо оно живёт и что прямо сейчас делает. Кроме того, в ShIoTiny5 есть режим работы "Single Mode", когда устройство в принципе не подключено к сети. И в этом случае без средств отображения информации - совсем грустно и тоскливо.
И, наконец, в-третьих - можно использовать микросхемы-драйверы светодиодов.
Эти варианты не исключают друг друга. Здесь я расскажу о третьем варианте, который реализован на ShIoTiny5 при помощи узла TM1637.
TM1637 - популярная и очень дешёвая микросхема драйвера 7-сегментного индикатора. Стоят модули на базе этой микросхемы "пятачок за пучок" на Aliexpress. Именно популярность и мизерная цена стали тем фактором, который определил поддержку этой микросхемы в ShIoTiny5.
Немного истории
Первую поддержку микросхемы TM1637 я ввёл ещё в ShIoTiny. Узел TM1637 умел выводить числа в разных системах счисления и разных форматах. Я уже было решил, что этого достаточно. Но, как обычно "гладко было на бумаге, но забыли про овраги".
Первое - это вопрос подключения индикаторов к чудесному чипу TM1637. Я, как человек старой закалки, привык к тому, что обычно люди следуют некоей логике.
Например, я свято верил, что 7-сегментные индикаторы в модулях с Aliexpress подключаются в порядке, согласно документации на TM1637. Это логично, так как при таком подключении символы на индикаторах отображаются в привычном порядке - слева направо, как они и записываются в коде программы. Но тут меня ждало ужасное разочарование. Например, вот в таком 4х-разрядном индикаторе, как на рисунке - всё в порядке. Нулевой символ - слева, третий - справа. Но, оказывается, не всё так просто. Следующим мне попался вот такой шикарный шестиразрядный индикатор, как на рисунке ниже. И что я увидел? А увидел я необъяснимое явление - его знаки были расположены в странном порядке - 2,1,0,5,4,3. То есть, если на первом индикаторе отображается число 1234, то на втором, это же число будет выглядеть как 321хх4, где буква "х" означает незадействованный символ индикатора, который будет просто тёмным.
Я не поручусь, что не существует и других способов перепутать индикаторы. Вообще таких способов - 719. Но то, что я могу точно сказать сколько есть способов перепутать 6 разрядов индикатора, не вселило в меня радости. Кроме того, 7-сегментные индикаторы это прекрасно. Но как в устройстве обойтись без отдельных светодиодов? Например, для индикации каких-то особых стояний и режимов. А еще для индикации какой-нибудь величины иногда удобно использовать светодиодные шкалы. Если их сделать из разноцветных светодиодов - смотрятся они просто потрясающе.
Поэтому я немного подумал. Потом ещё немного подумал. Потом поспал и подумал немного ещё... И придумал. Придумал разбить функции узла на несколько независимых узлов.
Узел TM1637 стал выполнять роль драйвера, который передаёт изображения символов (один символ - один байт) на модуль TM1637.
Появился узел Conv7Seg, который преобразует входное число в изображения символов для 7-сегментных индикаторов.
И появился ещё один узел - Scale - предназначенный для создания шкал.
Таким образом решилось несколько проблем.
Во-первых, мы можем выводить любое количество разрядов на дисплей в любом порядке. Разряды индикатора, в представлении узла TM1637 это просто отдельные входы-байты, каждый соответствует одному 7-сегментному индикатору. Один бит входа соответствует одному сегменту одного разряда индикатора. Поэтому производители могут как угодно перепутывать порядок разрядов на дисплее - это больше не страшно.
Во-вторых, мы можем как нам угодно управлять любым отдельным битом-сегментом любого разряда. Поэтому можно вместо любых разрядов 7-сегментного индикатора прицепить отдельные светодиоды и делать с ними всё что угодно. Ведь нечасто нам нужны все 6 разрядов, которые позволяет выводить TM1637. Обычно достаточно 4х разрядов, а то и меньше. Вот к неиспользуемым разрядам и прицепим хоть десяток светодиодов для того, чтобы устройство рассказало пользователю о себе всё.
В-третьих, модуль отображения шкал - Scale - без труда позволяет сделать на базе TM1637 шкалы, включающие в себя от 1 до 48 - светодиодов.
Как обычно - без примеров статья превращается в пустословие. Поэтому - слайды! Ну то есть - примеры.
Узел TM1637
Узел TM1637 предназначен для управления контроллером 6-разрядного 7-сегментного индикатора типа TM1637. Данный контроллер подключается по двум проводам — DIO и CLK. Ножки модуля ESP, к которым подключены сигналы DIO и CLK, задаются в меню привязки к выводам GPIO. Интерактивное меню привязки GPIO к узлу вызывается кликом мыши на поле GPIO, находящееся сверху от узла (на рисунке - красные надписи N/A). В меню параметров узла задаются следующие параметры.
Digits — задаёт количество используемых разрядов (символов) индикатора от 1 до 6. Число входов узла равно количеству разрядов.
Dot — режим вывода точки (сегмент H). В режиме «Input» - данные о состоянии точки берутся с соответствующего входа (бит 7). В режимах «1» - «6» положение точки жёстко фиксировано и она выводится всегда в составе разряда с соответствующим номером.
Узел TM1637 представляет каждый индикатор как набор 8-битов. Соответствие битов и сегментов индикатора представлено в таблице ниже.
Например, микросхема TM1637 подключена к ножкам GPIO12 (DIO) и GPIO14 (CLK). Индикатор используется 4-разрядный (как на первом фото). Выведем на него надпись SHIO. Программка для такого вывода показана на рисунке.
Обратите внимание, что ввод констант допустим в разных системах счисления - двоичной (0b), восьмиричной (0o), десятичной или шестнадцатиричной(0x). Для этого надо перед числом поставить соответствующий префикс, приведённый в скобках. После ввода число автоматически преобразуется к 10-й системе счисления. Но можно всегда посмотреть представление этого числа в различных системах счисления, подведя указатель мыши к этому числу. Выскочит всплывающая подсказка с представлением этого числа в разных системах счисления (на рисунке - число 63, код символа "O").
Как видим, с помощью узла TM1637 можно выводить любые комбинации сегментов индикатора. Но выводить константы это не то, что обычно нужно. Перейдём к выводу цифр.
Узел Conv7Seg — преобразователь чисел в коды 7-сегментного индикатора
Узел Conv7Seg служит для преобразования произвольного числа в код 7-сегментного индикатора с заданным количеством разрядов.
У узла один вход.
Количество выходов определяется заданным количеством разрядов 7-сегментного индикатора — от 1 до 16.
В поле параметров узла задаются следующие параметры:
Digits - количество разрядов индикатора, в которые нужно преобразовать входное значение от 1 до 16. Этим параметром определяется количество выходов узла.
Number - тип значения на выходе: Int, Hex, Float - соответственно целые 10-е числа, целые 16-е числа или число с плавающей точкой. В режиме Hex отрицательные числа не выводятся! Выводится значение «меньше минимального» (см. ниже).
Например, если вывод осуществляется на 4- разрядный индикатор, то число 12.42 будет выведено при разных значениях поля «Number» так как показано в таблице ниже.
Помимо цифр, имеется несколько особых случаев, когда на вход узла Conv7Seg приходит не-число, слишком большое или слишком маленькое число.
Если на вход поступает значение NaN (не-число), то во всех разрядах индикатора выводится стилизованная буква «n».
Если на вход поступает значение «больше максимального», возможного для вывода в заданном режиме (например, Inf — бесконечность или число 1234567 при выводе на 6-значный индикатор), то во всех разрядах индикатора выводится стилизованная буква «П».
Если на вход поступает значение «меньше минимального», возможного для вывода в заданном режиме (например, число -654321 при выводе на 6-значный индикатор), то во всех разрядах индикатора выводится стилизованная буква «U». Значение «меньше минимального» выводится также в режиме Hex при отрицательном числе на входе. Наглядно эти особые значения представлены в таблице ниже.
Попробуем вывести на индикатор текущий год - 2023. Для этого нам подойдёт такая схема, как на рисунке ниже.
Ну и, раз мы уже умеем выводить числа, то можно делать самое любимое, что делают самодельщики на индикаторах - часики. Часики, конечно очень современные и будут получать время по интернету с NTP-сервера. Схема таких часиков показана на рисунке ниже.
Эти часики получают время с сервера pool.ntp.org каждые 60 минут и устанавливают системное время ShIoIny5 в UTC+0.
Узел Get Time получает системное время в формате UnixTime и добавляет к нему заданное смещение - в нашем примере это Московское время UTC+3. Далее UnixTime передаётся в узел Split Time, вычленяющий из него день, месяц, год, часы, минуты, секунды, день недели. Нас интересуют только часы (hour) и минуты (min). Число часов преобразуется в код 2х разрядов 7-сегментного индикатора верхним узлом Conv7Seg, а число минут преобразуется в код 2х разрядов 7-сегментного индикатора нижним узлом Conv7Seg.
Замечу, что параметр Zeros (вывод ведущих нулей) узлов Conv7Seg установлен в состояние On. чтобы время выводилось как "00:00", а не как "0: 0".
Далее коды часов передаются на входы d0 d1 узла TM1637, а коды минут передаются на входы d2 d3 того же узла.
Параметр Dot узла TM1637 установлен в значение 2, чтобы всегда после значения часов выводился разделитель - двоеточие, если мы используем "часовой" модуль, как на первом фото в статье.
Ну, в общем, с числами, я думаю понятно. Подробности есть в инструкции по ссылке в конце статьи.
И последний узел - узел формирования линейных шкал Scale.
Узел Scale — шкала узел формирования линейных шкал
Узел «Scale» предназначен для преобразования входного значения в диапазоне 0..1 в представление последовательности бит для линейной шкалы.
Имеются опциональные функции индикации уровня «меньше нуля» и «больше единицы».
Предполагается, что шкала состоит из N светодиодов. Единица в i-м бите — светодиод i включён, нуль в i-м бите — светодиод i отключён.
Входное значение в диапазоне преобразуется в последовательность из N бит, в которой биты с номерами - равны 1, а биты с номерами - равны 0.
Далее, сформированная последовательность бит преобразуется в несколько байт. Число байт равно , где параметры Leds и Shift задаются в поле параметров узла. Деление в формуле — целочисленное.
Эти сформированные байты можно затем подать на входы узла управления выходами или светодиодами. Например, на входы узла TM1637. В этом случае микросхема TM1637 будет рассматриваться просто как драйвер, управляющий отдельными светодиодами, которые конструктивно объединены в одну или несколько шкал.
Параметр Leds задаёт количество светодиодов шкалы в диапазоне от 1 до 64.
Параметр Shift задаёт сдвиг 0-го бита шкалы относительно 0-го байта (выход d0).
Параметр Flash min задаёт режим «меньше минимального». То есть режим мерцания младшего, 0-го бита шкалы при значении на входе узла меньше нуля. Если параметр Flash min установлен в значение yes, то при появлении на входе шкалы значения меньше 0, младший, 0-й, бит шкалы начинает периодически переключаться с 0 на 1 и наоборот.
Параметр Flash max задаёт режим «больше максимального». То есть режим мерцания старшего, (N-1)-го бита шкалы при значении на входе узла больше 1. Если параметр Flash max установлен в значение yes, то при появлении на входе шкалы значения больше 1, старший, (N-1)-й, бит шкалы начинает периодически переключаться с 0 на 1 и наоборот.
Параметр Flash time задаёт период мерцания светодиодов в режиме «меньше минимального» и «больше максимального». Период задаётся в децисекундах (0.1сек) в диапазоне от 0.1 до 10 сек. По умолчанию, период мерцания равен 1сек (10 децисекунд).
Для того, чтобы нагляднее представить как работает шкала мы не будем её паять (это долго и не у всех получится), а просто воспользуемся тем же 4х-разрядным индикатором. Пусть наша шкала состоит из 31 светодиода, в роли которых мы (только для примера) используем сегменты нашего часового индикатора.
Счётчик считает с периодом 0.5 сек согласно установкам таймера.
Далее его значение преобразуется к диапазону . По мере возрастания параметра счётчика последовательно зажигаются сегменты индикатора, имитирующие светодиоды шкалы. Заметьте, что пока значение на входе отрицательно - самый младший светодиод шкалы мигает, показывая, что входное значение шкалы меньше минимально допустимого значения.
Ну вот и всё с примерами. Подробности в инструкции, а инструкция - по ссылке в конце статьи.
И вот, обладая всеми познаниями о выводе чисел на индикаторы сделаем простое, но иногда полезное устройство - комнатную метеостанцию + NTP часы.
Ещё один пример
Итак, комнатная метеостанция + NTP часы. Отображать будем всё только на индикаторе, без отдельных светодиодов. Но зато с не-цифровыми символами. Управление через интернет и публикацию данных пока опустим. Кому интересно - вставят сами.
Первый разряд индикатора используем в качестве индикации режима работы (старший разряд часов или символ - температура t, влажность H.
Для переключения режимов отображения - подключим ровно одну кнопку на GPIO2.
В качестве датчика используем тот, что есть. У меня был под рукой датчик AM2302 и я подключил его на GPIO13.
Ну и, наконец, сам 7 сегментный индикатор (такой, как на первом фото). Линию данных DIO я подключил на GPIO12, а линию синхронизации CLK - на GPIO14.
Схема-программа для ShIotiny5 (версия v0.25) получилась такая, как на рисунке.
Добавлять лишнее - связь и управление по интернету - я не стал, чтобы не усложнять пример.
Итак, как всё это работает?
Сначала рассмотрим со стороны пользователя. То есть того, кто жмёт кнопку и нечего о внутренностях не знает.
После включения устройство отображает время в формате ЧЧ:ММ. Это видно по двоеточию посреди индикатора.
Сначала, пока время с NTP-сервера не получено, отображается 00:00. Потом, когда значение времени будет получено с NTP-сервера, начинает отображаться время в заданном часовом поясе (в примере UTC+7). Промежуток времени от включения устройства до получения значения времени обычно составляет 5-10 секунд от включения при наличии связи с сервером NTP.
При каждом нажатии кнопки происходит циклическое переключение режимов "Время" -> "Температура"->"Влажность"->"Время" ...
В режиме отображения времени на индикаторе отображается значение часов и минут, а между ними - двоеточие. Модуль индикации взят часовой, как на первом фото, поэтому там вместо точки 2-го разряда стоит двоеточие.
В режиме отображения температуры первый разряд индикатора отображает символ "t". Второй символ - либо пустой (если температура положительна), либо знак "минус" - если температура отрицательна. А третий и четвертый разряды индикатора отображают значение температуры. Так как температура воздуха вряд ли опустится ниже -99С или поднимется выше +99С - то надеюсь, что двух разрядов для её отображения будет достаточно.
И, наконец, в режиме отображения влажности первый разряд - буква "H", второй разряд - пустой и не используется, а третий и четвертый разряды индикатора отображают значение влажности воздуха.
Вот и все функции нашего устройства со стороны пользователя.
Рассмотрим как это работает "изнутри", со стороны программы для ShIoTiny5. Будем рассматривать схему-программу по частям, выделенным из общей схемы-программы.
Значение времени с NTP-сервера мы получаем при помощи узла NTP Time. В качестве NTP-сервера задан "pool.ntp.org". Число 60 означает, что время будет синхронизироваться с сервером каждые 60 минут (1 час). Вы, конечно, можете задать свой NTP-сервер. Время мы получаем всегда в часовом поясе UTC+0. Получив значение времени, мы тут же устанавливаем его в качестве системного времени нашего устройства с помощью узла Set Time. Отметим, что пока значение времени не получено с NTP-сервера - на выходе узла NTP Time будет значение 0.
Системное время UTC+0 считывается и преобразуется во время заданного часового пояса с помощью узла Get Time. После этого, временная метка разбивается на составляющие - часы и минуты. Значение часов поступает на узел Conv7Seg где преобразуется в код 2х разрядов 7-сегментного индикатора с ведущими нулями. Значение минут поступает на мультиплексору выбора режима. Значение старшей цифры часов обрабатывается мультиплексорам знака/времени. Значение младшей цифры часов обрабатываются мультиплексорам режима/времени. Об этих мультиплексорах - ниже.
Итак, с синхронизацией времени устройства и получением отдельно часов и минут разобрались. Перейдём к выбору режима работы устройства пользователем.
Собственно, за выбор режима отвечает один счётчик, который так и называется - "счётчик режимов". Этот счётчик ещё маленький и поэтому умеет считать только до 2х. Кнопка выбора режима, которая подключена к к ножке GPIO2 модуля ESP8266, формирует импульс - число 1 - на выходе узла DInput. А при каждом "отпускании" выход узла DInput возвращается в состояние 0. Счётчик режимов считает количество этих импульсов. Так как счётчик умеет считать только до 2х, то после 3го импульса он сбрасывается в 0. Таким образом, при нажатии на кнопку, на выходе счётчика формируется последовательность 0,1,2,0,1,2... и т.д. Значение на выходе счётчика режимов - это номер режима работы устройства. Режим 0 - часы, режим 1-температура и режим 2 - влажность.
Датчик AM2302 подключён к мультиплексору выбора режима. На входе управления S0 этого мультиплексора подаётся номер режима 0-2. На выходе Q мультиплексора выбора режима формируется одно из значение: в режиме 0 (часы) - значение минут со входа i0, в режиме 1 (температура) - значение температуры со входа i1 и в режиме 2 (влажность) - значение влажности со входа i2.
Остановимся немного на индикаторе. Младшие два разряда - d2, d3 - отображают всегда число - минуты времени, градусы температуры или проценты давления.
Разряд d1 индикатора отображает или младшую цифру часов с двоеточием (в режиме 0 - часы) или знак (в режиме 1-температура) или ничего (в режиме 2-влажность).
Разряд d0 индикатора отображает или старшую цифру часов (в режиме 0 - часы) или символ "t" (в режиме 1-температура) или символ "t" (в режиме 2-влажность).
Проще всего управление младшими разрядами - d2 и d3.
Значение с выхода мультиплексора выбора режима преобразуется в свою абсолютное значение и подаётся на узел Conv7Seg где преобразуется в код 2х разрядов 7-сегментного индикатора с ведущими нулями.
Зачем нам преобразовывать значение с выхода Q мультиплексора выбора режима в абсолютное значение?
Всё очень просто. Значение температуры теоретически может быть отрицательным. Например значение температуры -27 градусов. Но чтобы отобразить число -27 нужно не 2, а три разряда индикатора. Поэтому, чтобы число всегда "влезало" в 2 разряда - оно берётся по модулю. А знак "минус", если он есть - формируется отдельно и записывается в разряд d1 индикатора как показано на рисунке ниже.
Знак "минус" это включенный сегмент G в разряде d1 индикатора. Остальные сегменты выключены. Сегменту G соответствует число 0x40 или 64. Формирователь знака предельно прост: если значение с выхода мультиплексора выбора режима отрицательно, то на выход Q мультиплексора генератора знака поступает значение 64. Если значение с выхода мультиплексора выбора режима положительно, то на выход Q мультиплексора генератора знака поступает значение 0 (все сегменты выключены).
Формирователь разряда d1 индикатора.Значение с выхода Q мультиплексора генератора знака поступает на входы i1 и i2 мультиплексора знака/времени. На вход выбора S0 мультиплексора знака/времени поступает номер режима. На вход i0 этого мультиплексора поступает код 7-сегментного индикатора - младшая цифра часов. Этот код предварительно логически складывается с числом 128, что соответствует сегменту H (двоеточие). Таким образом, в режиме 0 (часы) на выходе этого мультиплексора формируется код младшей цифры часов с установленным сегментом H - двоеточием. В режимах 1 и 2 на выходе мультиплексора знака/времени формируется знак числа - знак "минус" или "пустота". Данные с выхода мультиплексора знака/времени поступают на входом d2 7-сегментного индикатора.
На вход выбора S0 мультиплексора режима/времени поступает номер режима. На вход i0 этого мультиплексора поступает код 7-сегментного индикатора - старшая цифра часов. На вход i1 этого мультиплексора поступает код 7-сегментного индикатора - символ "t". На вход i2 этого мультиплексора поступает код 7-сегментного индикатора - символ "H". Таким образом, в режиме 0 (часы) на выходе этого мультиплексора формируется код старшей цифры часов. В режиме 1 (температура) - код символа "t" и режиме 2 (влажность) - код символа "H".
Надеюсь, что теперь понятно, как работает это несложное устройство и как пользоваться узлами индикации.
Заключение
Вот мы и рассмотрели узлы управления индикацией ShIoTiny5. Конечно, тут рассмотрены не все особенности работы узлов. Но, я надеюсь, что материал будет полезен.
Конечно, как всегда, я даю несколько полезных ссылок.
Если хотите высказать предложения и пожелания - пишите письма: shiotiny@yandex.ru