Следующая новость
Предыдущая новость

Красивое время. Как я сделал «умные» часы на трубках Nixie и ESP8266

09.04.2020 22:12
Красивое время. Как я сделал «умные» часы на трубках Nixie и ESP8266

Содержание статьи

  • Программирование ESP8266
  • SPI В ESP8266
  • Не все так просто
  • HV5622 и антикризисное решение
  • Пара слов об индикаторах
  • Wi-Fi и NTP
  • Эпоха UNIX и отсчет времени
  • Чуть-чуть конструктива
  • А что кроме часов?
  • Пишем сервер
  • Клиент
  • И даже более

Наверняка ты уже видел в интернете самодельные приборы с красивыми винтажными лампами, внутри у которых желто-оранжевые светящиеся цифры. Эти штуки называются «газоразрядные индикаторы» или Nixie tube. В этой статье я расскажу, как сделал из них часы с модулем Wi-Fi. Впрочем, можно не только использовать их как часы, но и выводить любую информацию — например, загрузку центрального процессора в десктопе.

Один из главных недостатков самодельных часов (да и не только самодельных, к сожалению) — точность хода невысока. Как эту проблему решают? Некоторые используют специализированные микросхемы с термокомпенсацией ухода частоты, например DS3231. По ключевым параметрам она заметно превосходит популярную среди радиолюбителей DS1307. С последней даже при удачно подобранном кварцевом резонаторе часы уходят на несколько минут в год.

Однако можно зайти и с другой стороны, а именно — воспользоваться серверами точного времени. Да, тогда устройству потребуется подключение к сети, но сейчас это уже не представляет особых трудностей. Кроме того, сразу исчезает проблема установки текущего времени. У часов может не быть кнопок вовсе. Это лучший интерфейс: просто включил, и они работают. Магия? Нет-нет, лучше — технологии!

Достаточно очевидный способ получить доступ к сети в самодельном гаджете — это использовать один из многочисленных модулей на ESP8266, например ESP12E. Моей первой мыслью было собрать часы на микроконтроллере (STM32F030 или аналогичном), подключить ESP12E по UART и взаимодействовать с модулем с помощью AT-команд. Это наиболее простой путь, но он не самый рациональный.

Действительно, ведь ESP8266 тоже очень неплохой МК с 32-битным ядром, поэтому вариант реализовать все в одном месте выглядел слишком соблазнительно. Однако при разработке и прототипировании пришлось столкнуться с рядом неочевидных трудностей. Часть из них удалось решить, часть пришлось обойти, и ниже я постараюсь рассказать обо всем в подробностях.

Программирование ESP8266

Взвесив все за и против, я решил писать код на С. MicroPython тоже смотрелся заманчиво, но в итоге тяга к минимализму взяла свое. Прошивка компилируется с использованием инструментов esp-open-sdk. Кстати, для Arch Linux есть соответствующий пакет в AUR, с его сборкой меньше всего проблем. Если ты никогда не имел дела с модулями ESP8266, то для быстрого старта рекомендую ознакомиться с каким-нибудь руководством в интернете.

Поэтому далее я не буду останавливаться на базовых вещах. Замечу лишь, что скорость прошивки ESP8266 можно значительно повысить по сравнению со стандартными настройками. Так, использование преобразователя USB — UART на основе FT232RL позволяет установить скорость передачи в esptool до 3 Мбит/с, что существенно больше предельной скорости FT232RL. Однако мой чип с такими настройками работал устойчиво. Получится ли это на других похожих микросхемах — СН340 или СР2102, я не проверял. Скорость задается с помощью ключа -b, а нужная секция Makefile с изменениями выглядит так:

flash:   $(ESPTOOL) -b 3000000 write_flash 0 $(TARGET).elf-0x00000.bin 0x10000   $(TARGET).elf-0x10000.bin 

SPI В ESP8266

Подобно тому как язык чукчей беден на слова, но богат на образы, в ESP12E мало выводов, но много интерфейсов. Поэтому разумно подключить блок индикации через какой-нибудь последовательный интерфейс, например SPI. В ESP8266 есть два таких интерфейса — SPI и HSPI — и ровно одна неочевидная засада, связанная с ними. Дело в том, что стандартный SPI используется для чтения из внешней флеш-памяти, содержащей прошивку. При неаккуратном обращении с интерфейсом в микроконтроллере возникнет конфликт доступа, что приведет к зависанию и перезагрузке.

И самое забавное: если большинство функций находится во внутренней RAM, то вся эта конструкция может даже успешно работать какое-то время, но неожиданно падать через несколько часов работы. Обойти эту проблему несложно — достаточно использовать HSPI вместо SPI. Стандартная библиотека, входящая в состав официального SDK, мне показалась неудобной, и я использовал стороннюю реализацию ESP8266_SPI_Driver. По умолчанию тут задана частота тактирования 4 МГц, порядок битов MSB first, SPI mode 1 (CPOL=0, CPHA=1) — более чем достаточно для моих задач. Для передачи используются макрофункции spi_tx8() и spi_tx32(), а сама инициализация интерфейса тривиальна:

spi_init(HSPI); 

Не все так просто

С самого начала я собирался реализовать статическую индикацию, для чего планировал взять два сдвиговых регистра 74HC595 и подключить к ним на выход четыре К155ИД1 (аналог SN74141). Однако в моих запасах нашлись только три такие микросхемы, а докупать их я не захотел. Цены на К155ИД1 сейчас кусаются, а в некоторых местах она стоит даже дороже, чем ESP12E в Китае. И тут мне на глаза попалась MAX7219, предназначенная для динамической индикации на семисегментных светодиодных панелях. И я задался вопросом: можно ли с ее помощью сделать динамическую индикацию на неоновых индикаторах ИН1? Забегая вперед, скажу, что можно, но коммутацию анодов придется устраивать на транзисторах.

Итак, берем MAX7219 и подключаем на выход (выводы сегментов) двоично-десятичный дешифратор К155ИД1. Здесь очень удачно совпало, что в MAX7219 выводы сегментов в выключенном состоянии подтягиваются к земле, а не переходят в Z-состояние. Поэтому К155ИД1 можно подключить напрямую. Коммутировать аноды я решил оптосборкой TLP627-4, которая должна быть достаточно быстрой для подобной задачи.

Схема индикации на MAX7219

Обрати внимание, что MAX7219 — это логика с уровнем 5 В, а у ESP8266 только 3,3 В. Следуя лучшим рекомендациям, здесь нужно ставить преобразователь. Однако в данном случае все прекрасно работает и без него, так что забудем о рекомендациях.

Красивое время. Как я сделал «умные» часы на трубках Nixie и ESP8266
Макет на MAX7219

Итак, собрали макет, подключили один индикатор, инициализировали MAX7219, отправили данные — работает! Подключили еще три индикатора, отправили данные — не работает. Неприятность, однако.

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

Красивое время. Как я сделал «умные» часы на трубках Nixie и ESP8266
Транзисторный ключ

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

Красивое время. Как я сделал «умные» часы на трубках Nixie и ESP8266
Динамическая индикация на сдвиговом регистре

Сдвиговый регистр тоже устойчиво работает c ESP8266 без преобразователя уровней. Данные периодически передаются по SPI, который ограниченно совместим с серийным интерфейсом сдвигового регистра (ранее это уже обсуждалось в статье про мобильный телефон). Каждая посылка представляет собой байт, четыре старших разряда которого отвечают за включение анодов, а младшие четыре разряда кодируют выводимую цифру. Проблему недостаточной скорости выключения оптопары удалось решить программно, заранее выключая анод за некоторое время до включения следующего.

#define send595(data) spi_mast_byte_write(SPI,data) uint8_t ind[4]={4,3,2,1};  void ICACHE_FLASH_ATTR user_init() {   ...   spi_master_init(SPI);   os_timer_setfn(&led_timer, (os_timer_func_t *) indicate, NULL);   os_timer_arm(&led_timer, 1, 1);   ... }  LOCAL void indicate(void *arg) {   static uint8_t n=0, i=0;   if (++i % 2) {     send595((1<<(n+4))|ind[n]);   } else {     send595(ind[n]);   }   n++;   if (n > 3) n=0; } 

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

Ты мог обратить внимание, что в этом коде используется драйвер из SDK, а кроме того, интерфейс SPI вместо HSPI. Последний момент доставил мне много проблем. Так, при попытке использовать Wi-Fi система даже отказывалась стартовать, тогда как без SPI Wi-Fi работал. И у меня ушло много времени, чтобы понять причины этого. А все из-за конкуренции с флеш-памятью! В итоге, когда искал первопричину этих проблем, я и отказался от использования динамической индикации.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

1 год

7690 р.

1 месяц

720 р.

Я уже участник «Xakep.ru»

Источник

Последние новости