Все началось, когда мое внимание привлек старый светодиодный дисплей, лежащий в ящике среди мелочевки и запасных деталей. Он сохранился еще со времен древних 386/486 ПК и мог отображать частоту до 99 МГц. Когда он был установлен на системном блоке в те времена, он показывал только две скорости, обычную и турбо, эти скорости работы центрального процессора выбирались специальной кнопкой. Фишка была в том, что сами цифры были желтыми, а надпись MHz (горящие непрерывно) светились красным. Такая комбинация цветов мне понравилась. *
*В те годы частота процессора менялась специальной кнопкой “Turbo”, и эта кнопка присутствовала на системном блоке, а частота отображалась на таком светодиодном дисплее. Прим. Переводчика.

Тогда я задумался, а можно ли собрать на основе этого циферблата часы. Оперируя всего двумя цифрами, мне пришлось бы мультиплексировать часы и минуты. Я решил, что в таком случае могу отображать 12:34 как 12H, сопровождаемое 34М.

Была и еще одна особенность, а именно то, что часть с MHz состояла из всего 7 «сегментов». М делилась на три сегмента, а именно на две боковые вертикальные палочки и центральную часть V. В H 2 вертикальные палочки также были отдельными сегментами, но центральная ее часть уже объединялась с верхушкой буквы z, чья нижняя часть < представляла последний 7-й сегмент. Это означало, что после H всегда будет отображаться «тире», т.е. 12:34 будет показываться как 12H-, а затем 34M. Пусть это будет фишка.

Каждый сегмент MHz состоял из двух последовательно соединенных красных светодиодов с прямым напряжением 3,6В. Желтые же цифры были представлены одиночными светодиодами с прямым напряжением 1,9В. Очевидно, что такой семисегментник изготавливался индивидуально для производителя ПК. Именно поэтому вы и не сможете воссоздать такие часы, если только не отыщите аналогичный экран, сохранившийся с тех времен. Тем не менее при желании вы можете изменить ПО (по большому счету исключить код, обрабатывающий мультиплексирование часов/минут) под использование с удобным 4-значным дисплеем.

Цель


Я собрал эти часы, чтобы решить следующие задачи:

  • Запрограммировать STM8, в частности STM8S103F6, в C при помощи SDCC и портированной стандартной библиотеки периферийных устройств (SPL).
  • Мультиплексировать часы и минуты на двух цифрах.

Подключение


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


Кстати, кнопки тоже от старого ПК, раньше они служили в качестве Reset’а. Для подачи питания на 7805 стабилизатор я приспособил восстановленную зарядку от телефона Nokia.
Паять пришлось довольно много соединений, что неудивительно при переделке не мультиплексированного дисплея в мультиплексированный, поэтому я даже был рад, что собирал всего одну плату. В последствии тестирование показало, что помимо нескольких коротких замыканий и непропаев, была еще пара косяков: я думал, что у транзисторных драйверов посадочное место EBC, но оказалось, что ECB. Ну это же очевидно! Пришлось переподключать провода. Причем переподключать их пришлось не только здесь, потому что еще я перепутал два контакта дисплея, поменяв местами сегменты b и g второй цифры.

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


Схема

Программное обеспечение


SDCC (Small Device C Compiler ) поддерживает архитектуру STM8, и мне понадобились только определить ресурсы процессора STM8, например такие как регистры. Было интересно, почему они не поставляются вместе с SDCC. Не буду углубляться в подробности всего этого приключения, но в итоге выяснилось, что изначально ST не предоставляли включаемые файлы и библиотеки по подходящей для открытых проектов лицензии. В конечном счете они осознали свою ошибку, но к тому времени по интернету уже гуляло много обходных путей. Тем не менее существовал вариант портирования SPL в SDCC. Вы можете прочесть инструкцию по сбору SPL под Linux, чтобы получить включаемые файлы и библиотеку, к плюсам которых можно отнести: улучшенное самодокументирование кода в случае его излишней подробности, наличие проверки ошибок использования, а также то, что SPL для STM32 аналогична, т.е. при необходимости вы уже будете знать, как ее использовать.

Кроме того, я использовал протопотоки Адама Дункельса для обработки переключения.

Прошивка для часов на базе MCU имеет несколько подсистем. Далее я указываю исходные файлы С, обрабатывающие каждую из этих подсистем. Может оказаться полезным обратиться к исходному коду.

  • код, отвечающий за хронометраж (tod.c), который считает миллисекунды, секунды, минуты и часы;
  • таймер периодичности (tick.c), обрабатывающий сканирование цифр и опрос кнопок;
  • дисплей (display.c), получающий время и преобразующий его в массив из 7-сегментных байтов для отправки на порт вывода;
  • обработчик кнопок (button.c), считывающий состояние кнопок;
  • системный модуль (mcu.c), устанавливающий начальную конфигурацию;
  • основная программа (clock.c), связывающая все модули.

Для хронометража используется Timer1, поскольку имеет больше возможностей и дополнительных опций, которые мне еще пригодятся. Частота CPU в 16 MHz поделена до значения в 64 Hz, которое затем пошагово увеличивает время дня, структуру которую содержат счетчики.

Timer4 используется для работающего на 500 Hz генератора тактов, который служит для динамического отображения цифр и опроса кнопок.

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

Имейте в виду, что в отличие от более простых микроконтроллеров, контакты сегментов берутся из комбинации портов, так как ни один из них не предоставляет все 8 бит в корпусе TSSOP-20. Это значит я не могу использовать байтовые операции для одновременной обработки всех сегментов, но вынужден циклически обрабатывать по одному сегменту за раз. Однако этот микроконтроллер достаточно быстр, поэтому в сравнении с периодом тактов излишняя нагрузка ничтожна.

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

Системный модуль инициализирует нужную конфигурацию микроконтроллера. В частности, я использую встроенный RC-генератор на 16MHz.

Основная программа вызывает процедуру инициализации каждого из перечисленных модулей, а затем входит в цикл тактов.

Модификации для мультиплексирования часов и минут


Для обработки мультиплексирования часов и минут я создал 2 массива вместо одного. Первый содержит две 7-сегментные цифры для часов плюс постоянный третий байт, представляющий сегменты H-. Второй массив содержит две 7-сегментные цифры для минут плюс постоянный байт, представляющий сегменты M.

В тактовом цикле при каждом изменении счетчика секунд, он проверяется. Если его модуль после деления на 5 будет от 0 до 2, то указатель циферблата переключается на массив минут, в случае же 3 и 4 он переключается на массив часов. В результате получается, что для, например, 12:34 он в течение 2 секунд показывает 12 H-, а затем в течение трех секунд 34M.

Это мультиплексирование понадобилось остановить при установке времени. В итоге при удержании кнопки прибавления часов циферблат показывает их до тех пор, пока она не будет отпущена. То же самое с кнопкой для минут. Небольшое замечание – при прибавлении минуты счетчик секунд сбрасывается до 0. Это позволяет синхронизировать часы с другими часами, установив одно и то же время в минутах, а затем увеличив их значение резким одновременным нажатием во время смены секунд.

Я реализовал еще одну особенность, а именно выделил красным цифрам удвоенный цифровой период, компенсировав тем самым пониженное напряжение светодиода. В итоге рабочий цикл желтых цифр составляет 25%, а красных 50%.

Доработки для стандартного 4-значного дисплея


Здесь я описал свои непроверенные предположения о том, что нужно сделать тем, кто задумает модифицировать мой код для управления стандартным 4-значным дисплеем.

Из оборудования вам понадобится дополнительный вывод порта для управления 4-й цифрой. Первым логичным кандидатом для этого является D1, но нужно помнить, что на использованной мной коммутационной плате – это также порт SWIM для прошивки исполняемого образа. Так что вам понадобится перемычка, которую можно будет снять при перепрошивке и установить обратно для работы. Еще один вариант – не использовать двоеточие и задействовать A3 для 4-й цифры.

Имейте в виду, что B4 и B5 задействовать нельзя, так как это контакты с открытым стоком для l2C, которые для включения катодного транзистора потребуют добавления подтягивающего резистора. Еще одна проблема в том, что B5 запускает мигающий светодиод. Думаю, вы могли бы приспособить его для 4-й цифры, тогда этот светодиод будет обеспечивать ток транзисторных драйверов для светодиодов. В этом случае свечение B5 будет означать, что часы работают.

В отношении ПО вы можете заменить один 4-байтовый массив на два раздельных 3-байтовых, тогда не потребуется переключения указателя между массивами. Естественно, число цифр увеличиться до 4, но это будет обрабатываться хэш-функцией, использующей оператор sizeof при добавлении вами еще одного элемента в объявления цифровых контактов порта. Кстати, при этом вы также избавитесь от необходимости определения для красных цифр дополнительного времени сканирования, так как в вашем случае все цифры будут одинаковы.

Можете смело делать форк моего репозитория, если возникнет желание опубликовать ваши изменения. Мой код открыт для использования под лицензией MIT.

Тестирование


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

Настройка отсчета времени


Для настройки тактовой скорости часов использовался генератор с числовым программным управлением. Этот способ я подсмотрел у K. C. Lee, который использовал его в своих часах, собранных на микроконтроллере семейства STM8.

Давайте конкретизируем пример, взглянув на изменения в tod.c. Вы можете увидеть, что Timer1 по-прежнему настроен на генерацию 64 прерываний в секунду. Однако теперь счетчик миллисекунд вместо отсчитывания до 64 считает до 32. Мы создаем аккумулятор, назвав его DDS_Accum, который увеличивается на (2^23 + корректировка) при каждом прерывании таймера. Когда DDS_Accum превышает 2^24, на что почти всегда уходит 2 прерывания, счетчик миллисекунд увеличивается, а 2^24 вычитается из DDS_Accum. Я выбрал возведение в степень 2 для переполнения и последующее вычитание, потому что так мы можем выполнить первое путем проверки битов, а второе побитовым маскированием, сделав код более эффективным.

Теперь рассмотрим, какой эффект корректировка оказывает на накопление. Если она нулевая, то схема действует просто как деление на два. Если корректировка отрицательна, то иногда накопление не будет превышать лимит, и увеличение миллисекунд счетчиком происходить тоже не будет, т.е. такт будет утрачиваться. И наоборот, если корректировка будет положительной, иногда накопление будет превышать лимит два раза подряд, порождая лишний такт. Проще говоря, отрицательная корректировка замедляет часы, а положительная ускоряет. Дробная корректировка определяется как корректировка/2^23. Так как это происходит до срабатывания счетчика секунд, мы не замечаем этих мелких колебаний, тем более что минимально отображаемый отсчет ведется в минутах.

Все это можно обобщить до множителей (прерывание таймера/скорость миллисекунд), которые не равны 2, но в более крупных множителей необходимости нет.

Результат


Результат можно увидеть на видео.


Видимо придется залепить красный светодиод черной изолентой, так как иначе из-за своей дикой яркости он будет засвечивать остальные цифры в темное время суток.

Файлы к статье: 4digittest.ino

Ссылки:

Breakout Boards
Instructions for building SPL on Linux
Репозиторий проекта irreproducible-clock