Содержание статьи
Один из главных недостатков самодельных часов (да и не только самодельных, к сожалению) — точность хода невысока. Как эту проблему решают? Некоторые используют специализированные микросхемы с термокомпенсацией ухода частоты, например 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 — это логика с уровнем 5 В, а у ESP8266 только 3,3 В. Следуя лучшим рекомендациям, здесь нужно ставить преобразователь. Однако в данном случае все прекрасно работает и без него, так что забудем о рекомендациях.
Итак, собрали макет, подключили один индикатор, инициализировали 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»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»