Давно хотел собрать часы на газоразрядных индикаторах. Еще в детстве с интересом разглядывал сетки внутри этих древних приборов. Удивительно, что насмотреться вдоволь получилось в век светодиодных экранов.
Схем для повторения в сети достаточно, но и вопросов к ним хватает. Как можно отказаться от микросхемы К155ИД1? Зачем такое сложное питание ламп? Зачем использовать библиотеку при обращении к модулю часов? По паре транзисторов в цепи анода это не слишком жирно? А что с гальванической развязкой?
В результате родилась мысль собрать часы целиком на оптронах и с питанием индикаторов от розетки через диод.
Основные преимущества данных часов:
- Простота схемы.
- Полная гальваническая развязка контроллера от ламп.
- Минимум деталей и их разновидностей.
- Очень скромный бюджет. Оптроны обошлись в 180 рублей за 20 штук, а их бы все равно пришлось заказать 10 (минимальная партия) при использовании микросхемы К155ИД1. Лампы подарил хороший человек.
- Для Вас я попытался подробно прокомментировать код и описать работу схемы.
Недостатки:
- Если аккуратно разбить лампу, воткнуть вилку фазой на катод и схватится за него и батарею… сильно ударит током. Ниже расскажу как поправить чтобы ударило не сильно.
- Если пробьёт диод VD1 сгорит конденсатор С5, если пробьёт конденсатор сгорит диод и может быть что-то еще.
- Очень скромный функционал.
Питание
В справочнике на ИН-8 рекомендуют питать её от сети через диод и ограничительный резистор без фильтра. Ресурс ламп хотелось продлить максимально, а думать минимально и я попробовал. Цифры в таком режиме целиком не засвечивались. Ну и выводить время пришлось бы синхронно с напряжением в розетке. Ламп четыре, а полупериод один. Пришлось бы пропускать, а это потеря яркости и пульсации. Уже фантазировал как питать пару ламп положительной и пару отрицательной полуволной. Бес путать перестал и я добавил конденсатор на 2 мкФ (можно меньше). Напряжение в среднем подросло и картинка получилась идеально четкой, а ресурс и так будем беречь включая лампы по очереди. До последнего момента было не ясно останется ли свечение таким же ярким при переключениях, но все обошлось. Рекомендую самостоятельно подобрать резистор R3. Динамическая индикация это не предел моих фантазий. Мерцания напрягают, но ради такой техники можно и потерпеть. В дальнейшем планирую максимально поднять частоту переключения. Сейчас пульсации заметны не сильно. Как в заводских часах или даже лучше. Точно лучше чем в приборной панели премиального автомобиля.
Ток потребляемый одной цифрой на сглаженном напряжении оставил 1,5 мА, что меньше паспортных 2,5. Уменьшение сопротивления резистора R3 приводит к засветке соседних цифр.
Уменьшить силу поражающего воздействия тока можно разделив резистор R3 на два. Но это необходимо проверить экспериментально. Один на фазу другой на ноль. В случае с батареей через тело не пройдет больше пары мА.
Можно еще добавить резистор на пару сотен Ом перед диодом, для уменьшения зарядного тока конденсатора при включении. Диод нужно выбирать с запасом. У меня ретро Д226Б.
Ардуино получает энергию от зарядки для телефона, к выбору которой я тоже подошел со всей безответственностью. Надежнее конечно взять небольшой трансформатор с диодным мостом и конденсатором. Напоминаю, что не все зарядки выдают 5 В. На плате Ардуино установлен стабилизатор, для работы которого нужна разница между входным и выходным напряжением. Моя зарядка выдает 6,5 В под нагрузкой и подключил я её к выводу VIN. Модуль часов получает питание уже от стабилизатора Ардуино, с вывода +5V. Если ваше зарядное выдает ровно 5 В высочайшего качества, лучше подключить его через USB разъём. Как это «высочайшее» качество скажется на точности хода не известно.
Оптроны
В каждый момент времени, одна конкретная лампа включена последовательно с двумя оптронами. Один подает «+» на анод, другой замыкает на «-» один из катодов. Такой режим работы позвонил применить всего один ограничивающий ток лампы резистор R3, один ограничивающий ток светодиода оптрона резистор R1 и один R2. Если при отладке у Вас включится сразу вывод D2 и D3 например, на два оптрона тока уже не хватит. Если в другой похожей схеме попытаться зажечь все оптроны через свой резистор, то можно серьезно перегрузить выводы микроконтроллера.
Кнопки
Кто бы знал что у Ардуино столько выводов? Люди зачем-то мудрят с аналоговой клавиатурой. Лично я шиканул по полной и раздал каждой по контакту и еще 2 осталось для будильника или ламп с секундами. Насколько хорошо конденсаторы C1-C4 справляются с подавлением дребезга не измерял, но нажимается все четко, хотя кнопки без щелчка. К выводам А0-А3 подключены подтягивающие резисторы встроенные в микроконтроллер. Другими словами кнопка находится под напряжением, а в момент нажатия замыкает его на землю.
Монтаж и корпус
Пожалуйста не смейтесь. Я честно пытался процарапать дорожки, изучить программу для рисования схем и плат, но время и дети и солнце на улице... Поздно уже заигрываться. Залудил проводок и быстренько все соединил. Благо все идет по порядку и почти ничего не пересекается. Расстояние между лампами тоже пока не известно. Провода решают эту проблему. Картон использован благородный! Обложка от руководства на гидроакустический комплекс моего года выпуска.
Корпус конечно нужно исполнить красиво. Вещь дизайнерская.
Программа
Максимально все прокомментировал. Если для Вас не все сразу понятно, лучше ознакомиться с булевой алгеброй, содержанием регистра модуля часов, прерываниями по изменению состояния, методами работы с портами через регистры.
Если вкратце то за один проход выводятся 4 цифры. Сделать это нужно максимально быстро. Тесть на каждую лампу должно приходиться близкое к 1/4 всего времени выполнения главного цикла. В это же время нужно успеть проверить срабатывание прерывания по изменению состояния и изредка выполнить чтение данных из часов. Если кнопка была нажата то в промежутке в модуль пишется новое время.
Функционал можно расширить, но мне главное чтобы светилось теплым ламповым светом, а это как раз то место где он действительно нужен.
#include <Wire.h> //Подключаем библиотеку для работы с шиной I2C (для обмена данными с модулем часов) byte propusk=0; byte minutes; byte hours; byte minutes_units; byte minutes_tens; byte hours_units; byte hours_tens; boolean minutes_plus=0; boolean minutes_minus=0; boolean hours_plus=0; boolean hours_minus=0; byte byte2pin[3][10]={{B00000000,B00000001,B00000010,B00000011,B00000100,B00000101,B00000110,B00000111,B00001000,B00001001}, {B00000001,B00000010,B00000100,B00001000,B00010000,B00100000,B01000000,B10000000,B00000000,B00000000}, {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000001,B00000010}}; //Объявляем массив-дешифратор, для преобразования числа в номер вывода. Вторая строка отвечает за выводы D0-D7, третья D8-D9 void setup() { DDRD=B11111111; //Настраиваем выводы D0-D7 как выходы. Монитор порта работать перестанет (заняли выходы D0 и D1) DDRB=B11111111; //Настраиваем выводы D8-D13 как выходы pinMode(A0,INPUT_PULLUP); //Настраиваем выводы A0-A3 как входы. Подключаем подтягивающие резисторы pinMode(A1,INPUT_PULLUP); pinMode(A2,INPUT_PULLUP); pinMode(A3,INPUT_PULLUP); delay(1000); //Добавляем задержку против ложных срабатываний прерываний (перевода часов) при включении питания PCICR=B00000010; //Включаем прерывания по изменению состояния на аналоговых выводах перечисленных в PCMSK1 PCMSK1=B00001111; //Только выводы A0-A3 будут использоваться для запуска прерывания (одного на все выводы) Wire.begin(); //Запускаем I2C } ISR(PCINT1_vect) { //Обработчик прерывания выполняется 2 раза за одно нажатие. На нажатие и отпускание if (!digitalRead(A0)) minutes_plus=1; //Так как только при нажатии вывод замыкается на землю if (!digitalRead(A1)) minutes_minus=1; //кнопка срабатывает 1 раз за одно нажатие if (!digitalRead(A2)) hours_plus=1; if (!digitalRead(A3)) hours_minus=1; } void loop() { if (propusk>10) { //Обращение к часам происходит в 10 раз реже чем вывод времени. Нужно оставить больше время //для свечения ламп и не дёргать часы лишний раз. Значение > 20 ухудшает отклик кнопок. Wire.beginTransmission(0x68); //Начинаем работу с часами по адресу 0x68 (104). Адрес прошит в часы на заводе Wire.write(0x01); //Чтобы прочитать нужно указать с какого места начать. Начинаем со второго регистра (минуты) Wire.endTransmission(); //Не логично но порядок обязательно такой, иначе будет моргать при смене часов Wire.requestFrom(0x68,2); //Сообщаем, что собираемся прочитать 2 байта minutes=Wire.read(); hours=Wire.read(); minutes_units=minutes&B00001111; //Очищаем старшие 4 бита (десятки) минут. Остаются только единицы minutes_tens=(minutes&B11110000)>>4; //Очищаем и сдвигаем на 4 бита вправо десятки минут. Получаем нормальное число hours_units=hours&B00001111; hours_tens=(hours&B00110000)>>4; //В десятках часов очищаем еще и старшие 2 бита. Там настройка 12/24 формат времени propusk=0; } propusk++; if (minutes_plus) { //Время на digitalRead не тратим. Лампа горит дольше. О длительности нажатия не беспокоимся Wire.beginTransmission(0x68); Wire.write(0x00); //Начинаем с регистра секунд, чтобы сбросить их при переводе минут Wire.write(0); //Сбрасываем секунды. Сколько байт будем писать, как при чтении, указывать не нужно if (minutes_units<9) Wire.write(minutes&B11110000|minutes_units+1); //Очищаем от единиц минут и пишем туда новые else if (minutes_tens<5) Wire.write(minutes_tens+1<<4); //Новые десятки минут сдвигаем на их штатное место else if (minutes_tens==5) Wire.write(0); Wire.endTransmission(); //При записи данных порядок действий отличается minutes_plus=0; } if (minutes_minus) { Wire.beginTransmission(0x68); Wire.write(0x00); Wire.write(0); if (minutes_units>0) Wire.write(minutes&B11110000|minutes_units-1); else if (minutes_tens>0) Wire.write(B00001001|minutes_tens-1<<4); //К новым десяткам минут добавляем 9 в единицы else if (minutes_tens==0) Wire.write(B01011001); //Пишем 59 Wire.endTransmission(); minutes_minus=0; } //Далее бит формата 12/24 сбрасывается в 0 (24). Кому нужен 12 часовой формате следите за ним if (hours_plus) { Wire.beginTransmission(0x68); Wire.write(0x02); //Начинаем с регистра часов if (hours_units==3&&hours_tens==2) Wire.write(0); if (hours_units<9) Wire.write(hours&B00110000|hours_units+1); else if (hours_tens<2) Wire.write(hours_tens+1<<4); else if (hours_tens==2) Wire.write(0); Wire.endTransmission(); hours_plus=0; } if (hours_minus) { Wire.beginTransmission(0x68); Wire.write(0x02); if (hours_units>0) Wire.write(hours&B00110000|hours_units-1); else if (hours_tens>0) Wire.write(B00001001|hours_tens-1<<4); else if (hours_tens==0) Wire.write(B00100011); Wire.endTransmission(); hours_minus=0; } PORTD=byte2pin[1][minutes_units]; //Пишем в один из выходов порта D (выводы D0-D7) единицу отвечающею //за включение одного из катодов (соединение с его землей) PORTB=byte2pin[2][minutes_units]|B00000100; //Для цифр 8 и 9 задействуем порт В (выводы D8 и D9). //Включаем лампу единиц минут (L1) добавляя в порт В B00000100 (соединяем анод с + питания) delay(2); //Держим лампы включёнными немного. Пробовал разные значения PORTD=0; //Отключаем все катоды и анод для предотвращения засветки соседних символов PORTB=0; delay(1); //на недолго PORTD=byte2pin[1][minutes_tens]; PORTB=byte2pin[2][minutes_tens]|B00001000; delay(2); PORTD=0; PORTB=0; delay(1); PORTD=byte2pin[1][hours_units]; PORTB=byte2pin[2][hours_units]|B00010000; delay(2); PORTD=0; PORTB=0; delay(1); PORTD=byte2pin[1][hours_tens]; PORTB=byte2pin[2][hours_tens]|B00100000; delay(2); PORTD=0; PORTB=0; delay(1); }
Спасибо за внимание! Пишите если есть предложения по упрощению, оптимизации и устранению ошибок.
Комментарии (18) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
Высоковольтный транзистор, такой как MPSA92 или MPSA42, стоит около пяти рублей в одном известном и недешевом магазине. На вашу конструкцию получится те же 90 рублей.
[Автор]
Про программирование DC-DC для часов первый раз слышу.
[Автор]
Мне кажется самым логичным было бы в ds3231 настроить вывод на 1 гц. и ловить его на внешнем прерывании, в мк время считать инкриминированием секунд. на динамический вывод бросить все ресурсы.
[Автор]
А вот Динамического управление - это поганенько. И проблемма то, что бегают ёжики в соседних лампах и задавить их ни как не получается.А хотелось БЫ!
в статике всё клаасно! Но народец жадный. Всё холяву хочет. По поводу программы ... я пишу только на ASSMBLER и О ЧудО! И овцы сыты и волки целы. Динамическое управление вот где дерьмо зарыто и ни чем не подавить эти помехи в сосених лампах.
[Автор]
[Автор]
[Автор]
[Автор]