Наверняка ты уже видел в интернете самодельные приборы с красивыми винтажными лампами, внутри у которых желто-оранжевые светящиеся цифры. Эти штуки называются «газоразрядные индикаторы» или 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

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

Макет на MAX7219
Макет на MAX7219

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

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

Транзисторный ключ
Транзисторный ключ

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

Динамическая индикация на сдвиговом регистре
Динамическая индикация на сдвиговом регистре

Сдвиговый регистр тоже устойчиво работает 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 работал. И у меня ушло много времени, чтобы понять причины этого. А все из-за конкуренции с флеш-памятью! В итоге, когда искал первопричину этих проблем, я и отказался от использования динамической индикации.

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

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

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

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


3 комментария

  1. Аватар

    Artem Kashkanov

    09.04.2020 в 16:54

    Круто! Теперь мне не придется писать 90% кода для своих часов на ESP12F и ИВ-6 🙂 И есть шанс их таки допаять.

    У индикаторов ИН-1 еще одна засада — индикаторы не самого лучшего качества.
    Корпуса для часов нет и не планируется?

    • Аватар

      Candidum

      09.04.2020 в 17:04

      Качество у ИН-1 прямо скажем никакое) А корпус тут минимальный — изогнутая пластинка из оргстекла, одновременно закрывает плату и является подставкой, на мой вкус симпатично.

  2. Аватар

    Dimon90

    09.04.2020 в 23:52

    На ютубе канал есть АлексГивер, он там уже кучу вариантов таких часов сделал, со всякими функциями и эффектами, только на Ардуино)) Выглядят прикольно, тоже все думаю сделать))

Оставить мнение