еще обсуждение с форума по покупкам в интернет. (поиск – часы на ИН-1) на ИН-14 ИН-12
мою сборку смотрим на fb и в разделе Фонарик на светодиоде.
Фонарик.. не совсем так – это что там за огонь горит как фара от трактора что ли?
Здесь про часы – самодельный фонарь на светодиоде в записях справа. Часы делают из советских индикаторов года с 2006, уже больше 100 разных конструкций. Для школьника студента самодельшика (цы). 3 штуки разобрал и расписываю как делал, 2 покупные но только платы , без переделок никак. обзор нескольких конструкций.
Плазменный шар, катушка Теслы – в других записях. с яндекса перейти на оригинал тут 100 картинок и видео.
Тёплый ламповый свет или часы на газоразрядных индикаторах ИН-12

Здравствуйте, уважаемые читатели. Давно я хотел собрать часы на газоразрядных индикаторах, но всё катастрофически не хватало времени, наконец то я закончил этот проект. Под катом немного о том что такое газоразрядные индикаторы, а также о том как я собирал часы, начиная со схемы и заканчивая корпусом.ВведениеЕсли верить википедии, первые газоразрядные индикаторы были разработаны в 50-х годах прошлого века. За рубежом такие индикаторы называют «Nixie», название получилось от сокращения «NIX 1» — «Numerical Indicator eXperimental 1» («цифровой индикатор экспериментальный, разработка 1»). В данных часах используются знаковые индикаторы советского производства типа ИН-12Б.
По конструкции они из себя представляют стеклянную колбу внутри которой десять тонких металлических электродов (катодов), каждый из которых соответствует одной цифре от 0 до 9, электроды сложены так, что различные цифры появляются на разной глубине. Также присутствует один электрод в виде металлической сетки (анод), располагается перед всеми остальными. Колба наполнена инертным газом неоном с небольшим количеством ртути. Когда между анодом и катодом прикладывается электрический потенциал от 120 до 180 вольт постоянного тока, вблизи катода возникает свечение, загорается соответствующая цифра. За этот мягкий оранжевый свет и ценят эти индикаторы.Дополнительная информацияЕсли быть точным, то в лампах ИН-12Б присутствует ещё один катод — в виде точки, он в данных часах не используется.Также в данных часах для разделения часов и минут используется ещё один газоразрядный индикатор — ИНС-1Индикация осуществляется через линзовый купол баллона, выглядит как светящаяся точка оранжевого цвета.
Схема Схема часов была найдена на просторах сети, автор Тимофей Носов возможно. В основе её микроконтроллер PIC16F628A и советская микросхема К155ИД1, представляет собой высоковольтный дешифратор управления газоразрядными индикаторами.
Питание ламп реализовано с помощью повышающего импульсного преобразователя, собранного на полевом транзисторе, индуктивности, конденсаторе и диоде, сигнал ШИМ генерирует микроконтроллер.(thedangerousprototype поиск) В данной схеме используется динамическая индикация, микроконтроллер с помощью дешифратора К155ИД1 управляет катодами сразу всех ламп, синхронно управляет анодами ламп через оптопары. Скорость переключения ламп происходит с высокой частотой, а так как газоразрядным индикаторам, как и любой лампе, нужно время чтобы потухнуть, то мерцания человеческий глаз не видит (скажу больше — не видит даже камера).
В схеме реализовано резервное питание на элементе CR2032, при отключении питания индикация тухнет, а часы продолжают идти.Электронная часть
Схема часов разделена на две части — плата с лампами и основная плата устройства.Ссылка на архив с файлом для Splint Layout — тут
С помощью ЛУТ сделал две платы
Собираем плату с лампамиЛампы мне достались со старой советской техники, собственно эта находка и побудила меня собрать эти часы.
Собираем основную плату
Платы соединяются через разъемы PLS и PBS, которые припаиваются со стороны дорожек. Вот так выглядит в собранном виде:Микроконтроллер PIC16F628A покупал — тут
Оптопары покупал — тут
Полевой транзистор IFR840 — тут
Остальное было в наличии, или нашлось по месту.
Осталось прошить микроконтроллер. Прошивать будем с помощью программатора PICkit2, покупался давно — тут
Запускаем программу PICkit2 и прошиваем наш микроконтроллер
прошивкаПосле прошивки включаю часы… а цифры не светятся, мигает только секундный индикатор (ИНС-1). После нашел свою ошибку, в цепи питания ламп вместо резистора 4,7К был установлен 47К. После замены схема заработала, надо делать корпус.
Корпус
Остался у меня кусок бруса бука, это тот же бук что использовался для изготовления корпуса «шайтан коробочки» из моего предыдущего обзора.
Сначала хотел вырезать корпус на ЧПУ станке, договорился со своим товарищем работающим на мебельном производстве. Но, как бывает, то нет времени, то срочно надо выполнить другую работу. Короче, после месяца ожидания, решил сделаю сам.
Вырезал заготовку под будущий корпус, разметил
Вырезал полость под внутренности, это был сам трудоёмкий этап. Сначала высверливал, потом лишнее убирал стамеской, после зашкуривал.
Стамеской сделал углубление для стекла и задней панели, приклеил упоры внутри корпуса, все пропитал льняным маслом
Из затемнённого стекла вырезал кусок нужного размера
Сделал заднюю панель, с отверстиями для кнопок и разъёма питания
Собрал всё вместе, вид спереди
Вид сзади
Для того что бы часы стояли немного под наклоном, на днище приклеил две резиновые ножки
В случае редкого включения отдельных индикаторных катодов и активности других, частицы металла, распыляемого работающими катодами, оседают на редко используемых, что способствует их «отравлению». В устройстве реализован метод борьбы с этим явлением, перед сменой минут происходит быстрый перебор всех цифр во всех лампах. Демонстрация как это происходит:
Из функционала — часы, будильник, настройка яркости. Управление осуществляется тремя кнопками — «больше», «ок» и «меньше».
Нажатием на кнопку «ок» перебираются следующие режимы:
– настройка часов текущего времени (ЧЧ _ _);
– настройка минут текущего времени (_ _ ММ);
– настройка часов будильника (ЧЧ._ _);
– настройка минут будильника (_ _.ММ);
– настройка текущего дня недели от 1 до 7 (0 _ _ 1);
– срабатывание будильника в понедельник (1 _ _ 1);
– срабатывание будильника во вторник (2 _ _ 1);
– срабатывание будильника в среду (3 _ _ 1);
– срабатывание будильника в четверг (4 _ _ 1);
– срабатывание будильника в пятницу (5 _ _ 1);
– срабатывание будильника в субботу (6 _ _ 0);
– срабатывание будильника в воскресенье (7 _ _ 0);
– яркость свечения ламп от 0 до 20 (8 _ 05);
– почасовой сигнал с 9:00 до 21:00 (9 _ _ 1).
Вот так выглядит эта красота в темноте
В итоге имеем красивую вещь, сделанную своими руками. В будущем возможно сделаю другие часы в другом корпусе, есть одна задумка.
Всем спасибо за внимание.Понравилось 209
dangerousprototypes.com
Topic: Freeformed Nixie Tube clock previous topic – next topic
Freeformed Nixie Tube clock
October 09, 2012, 02:01:52 pm
If you combine Ian’s adventure into the world of Nixie tubes with my freeformed Litte Wire clone you get something like this:
[attachment=0]
It’s a clock made of a single IN-1 Nixie tube controlled by a ATMega8. The Mega8 directly controls 10 pcs of MPSA42 high voltage transistors for lighting up the filaments in in Nixie. It also generates the high voltage required for the tubes by a pwm output connected to a IRF520 N-FET and the usual inductor and fast recovery diode.
Unfortunately I’ve lost the schematics and firmware many years ago…
Here’s a link to a youtube movie showing the clock in action.http://http://youtu.be/06-RMMxYA1Q?hd=1 LethalNixieCube.jpg 469.45 KB, 1280×960 – viewed 17821 times
Re: Freeformed Nixie Tube clock
Reply #1 – October 09, 2012, 03:32:29 pm
You are truly an artist. That thing looks great and functional to. Nice video to. How long did it take to build?
- Корпус можно сделать из оргстекла. В советское время его было проще найти конечно.
- acrylic или поли метил метакрилат оно же































Полезные добавки в загрузках – прошивка , цоколевка ламп ИН-14 ИН-16 – поменьше ИН-12. Можно взять и готовую плату на Али она есть сейчас. Тогда цоколевка ламп точно пригодится.
Рис. 1 Газоразрядный индикатор ИН8
В стеклянном баллоне, наполненном неоном (наполнение обозначают черной точкой), на тонких металлических стойках размещены одна за другой (пакетом) проволочные электроды в форме цифр от 0 до 9. Эти электроды – катоды индикатора, которые обозначают на схеме небольшими кружками с выводами от них. Форму н размеры цифр делают такими, чтобы те из них. которые находятся впереди, возможно меньше перекрывали собой расположенные сзади.
Функцию анода выполняет тонкая сетка, размещенная перед пакетом цифр, через которую, хорошо видно свечение всех катодов цифр. От всех катодов и анода сделаны гибкие проволочные выводы, нумерация которых идет в направлении движения часовой стрелки (если смотреть на них со стороны дна баллона), как показано на рис. 1,б. Другой вариант схемного обозначения индикатора представлен на рис. 1,в.
ИН-14 Индикатор тлеющего разряда. Катоды в форме арабских цифр высотой 18 мм и двух запятых. Индикация осуществляется через боковую поверхность баллона. Оформление — стеклянное, с гибкими выводами. Масса 20 г.
ИН-18 Индикатор тлеющего разряда. Катоды в форме арабских цифр высотой 40 мм. Индикация осуществляется через боковую поверхность баллона. Оформление — стеклянное. Масса 35 г.
Цоколевка индикаторов ИН-8-2, ИН-12Б, ИН-14, ИН-16

Цоколевка индикаторов ИН-1, ИН-2, ИН-4,ИН-8, ИН-12А


с немецкими лампами Z570M или Tesla ZM1082T

Проект Разработка Настройка . Изделие Прошивка схемы и возможно платы. (не очень я их делаю если не надо вдруг больше 5 штук. Или вообще приспосабливаю готовые модули – в этом случае подходит как и с фонарем).
Вариант собрать все на железной логике и поставить часовой кварц 32767 герц.
Уже такие лежат на антресоли – спрятал их а то там корпус не очень красивый, листы оргалита и картонка, деушки выбросить могут . Логика и ИВЛ1-7/5 вроде как, не очень много корпусов. 30 лет работали и сейчас заработают если включить. Зеленое свечение люминофора вроде не ослабло .
Лампы ИН-14 in14 nixie tube 4 штуки и 2 in16 ИН-16 так красивее. Перевернутая двойка вместо пятерки в глаза не бросается.

Не идеально хоть и работает. Я переделываю повышающий и ставлю понижающий преобразователь, энергию батарей наполовину превращать в тепло это неправильно. Микроконтроллер быстрый и экономичный, на нем же делаю.
Схема. Поскольку работает от батареи – сейчас просто усиленная от ноутбука, а потом будет 3.7 вольта, источник питания однозначно на Мотороле MC34063 MC33063 лучше, наш аналог если что эмбарги всякие К1156ЕУ5, наша микруха точно выдерживает 1.6 ампера а оригинальную лучше не перегружать, 1.5 и ограничитель тока 0.20 Ом. 5 вольт от нее же лучше, а если питание все таки 12 то можно маленький стабилизатор AMS1117.
Вот что удалось купить прямо сейчас за полчаса (Москва Митино). BOM / список деталей. mc34063 кт837е irf640ns.
stm8s003f3. если так то uln2003 и 74hc595a . (К155ИД1 К555ИР8 остались скорее в Минске только). Надо сдвиговые регистры потому что у микроконтроллера лапок не так много всего 20. Сборка транзисторов uln2003 выдерживает 60 вольт , на лампах 180 но там есть ограничение через общий диодик. Оставшихся 120 вольт не хватает для зажигания разряда и ток не идет, на включенной цифре 0 вольт а на выключенной 60 а относительно анода 120 вольт. Как и у всех неонок – аноды подключаются через 30 килоом. Срок службы 10 лет и больше, электроды почти не испаряются а от эффекта отравления помогает перебор всех цифр. Вариант замены микроконтроллера stm32 а то и ардуинка atmel mega328p. на железной логике трудно потом переделать и 30 а то и больше корпусов это прямо компьютер Синклер. Если кто такое помнит Ленинградский вариант.. Кстати на логике 74HC будет не такой большой ток потребления. Китайская плата с лампами кушает 0.3 ампера от 12 вольт при включенных лампах но без светодиодов подсветки. на китайской плате часы DS3231. такой же чип заказываю – в Митино не оказалось а все остальное есть. Есть и лампы ГРИ но кое где можно купить дешевле, со складов.

Это очень похожая плата из Китая. На ней запаяны лампы ИН-14 украинские и 2 штуки ИН-16 и у маленьких просто загнуты выводы чтобы светились нужные цифры.

Проверено на практике. 12 вольт на затвор . И не с микроконтроллера – а если с программой сбой то все деталюшки менять ?? А с проверенного чипа который специально для такого сделан 30 лет уже как – больше. Учим его описание только – datasheet и штуки 3 appnote. MC34063 .

схема повышающего модуля. вроде верно, от 12 вольт. Выводы у 34063 слева направо и сверху вниз 1 7 3 4 6 8 2 5. Поверх R44 припаять медную проволочку лучше. Ниже доделка известной платы с Али по этой схеме.

us1m irf640ns 470nF 300k 3k2 делитель и 330 ом на землю а на затвор полевика напрямую, так можно если 12 вольт но китайцы сэкономили с усилителем на 2 транзисторах как выше на схеме правильнее, меньше будет греться полевик, усилитель на комплементарной паре справится с большим током заряда и особенно разряда емкости затвора и транзистор быстрее будет закрываться с меньшей потерей мощности на нагрев * при 12 вольтах и 170 пикофарадах там амперный импульс 180 наносекунд кто не верит может 0.05 резистор запаять и на нем осциллой посмотреть . Можно вместо кт3102 поставить диод Шоттки – с током заряда микросхема справится до 1.5 ампера, а вот второй транзистор нужен . Схема почти та же что 2-й фонарь на LED COB 6 ватт 207 вольт, там 2 чипа Моторола и транзистор КП813, он на 200 вольт и 35 ампер или 100 в импульсе, катушка там намного больше из-за работы при 3 вольтах и еще большей в 2 раза мощности – ампер на метр в катушке болише нельзя поэтому там металлопорошок альсифер а не феррит – получается в 8 раз большая энергия в индуктивности нужна, для меньших потерь лучше даже трансформатор.
Проверю потребляемый ток после переделки – напряжение 12 вольт достаточно если 5 то надо 2-ую микросхему, а вот после установки транзисторов что изменится , индуктор тоже другой – возьму китайский 10А inductor на зеленом колечке он только немножко побольше – феррит или обмотка на плоском сильно греется. Если получится то ток потребления будет 150 миллиампер а не 350 от 12 вольт. *170 ма без подсветки и 200 с подсветкой и вкл. всех ламп, ну да можно батареек в 2 раза почти меньше покупать.
Совсем начинающим можно для большей надежности еще и для понимания работы техники 20 века поставить понижающий трансформатор и конечно диодный мост и конденсатор. Заказать на Митино или найти с лампового приемника или телевизора. 16 килограм весом не нужно а вот современный вполне тороидальный можно и самим сделать – не советую – сказать что нужна обмотка на 220 вольт и выход 170 и 5 вольт. 5 вольт подобрать измеряя после выпрямителя и конденсатора на 2000 микрофарад хотя бы. Отмотав или домотав 1 виток.


Номиналы деталей в схеме преобразователя:
Ct=379 пФ
Ipk=1400 мA
Rsc=0.214 Ом
Lmin=41 мкГн
Co=470 мкФ 6.3V
R=180 Ohm
R1=1k; R2=3k (5В) 700ma 3.5W max этот без внешнего транзистора. Там ток потребления по 5 вольтам в 10 раз меньше.
После замены половины деталек и ремонта платы из-за сгоревшего ams1114 конечно поставлю по этой схеме понижайку. Это в объемном монтаже занимает место как 2 smd индуктивности ну чуть больше. Для 5 штук часов платы не делаю, собираю на макетке и из модулей. Источник как в фонаре – залить клеем из пистолета.
теперь контроллер управляющий этими часами.
В библиотеке не используется POSIX формат времени, дату (год:месяц:день_недели:число) я храню в самом календаре и в отдельном суточном счетчике я храню количество секунд прошедших с начала суток. Если количество секунд превышает 86400(количество секунд в сутках), то вызывается метод add_day(), который индексирует календарь на один день. Такой подход позволяет избежать расчета {год:месяц:день_недели:число}, каждый раз, когда потребуется узнать час или минуту. <p></p> <p> Календарь хранится не в структуре, а в простом массиве из семи байт. Так проще в цикле читать его из RTC. Для доступа к полям календаря служит нумерованный список: </p> <pre class="CodeC"><span class="Type">enum</span> FIELD { YEAR=<span class="Constant">6</span>, MONTH=<span class="Constant">5</span>, DATE=<span class="Constant">4</span>, DAY=<span class="Constant">3</span>, HOUR=<span class="Constant">2</span>, MINUTE=<span class="Constant">1</span>, SECOND=<span class="Constant">0</span>};
После того как с управлением индикатором все стало ясно, пришла пора подумать о “мозгах” часов. Может быть, чтобы выглядеть умнее, стоило выбрать серьезный контроллер, и воспользоваться профессиональными средствами разработки и отладки… Или пойти еще дальше и применить ПЛИС. Но я решил рискнуть навлечь на свою голову критику профессиональных программистов и воспользоваться ARDUINO. Простая среда разработки и простые аппаратные средства – именно то, что нужно для простого и нетребовательного ни к скорости, ни к ресурсам проекта:).
невероятно сложно перейти на импульсные источники питания. Всегда же собирался транс выпрямитель 2 кондера и кренка ну 7805 или 7812 а то и без нее напрямую, так вроде надежнее. А перейти на какие то микроконтроллеры это совсем новое но придется, это же тоже цифра, логику 133 продали на золото а 155 закончилась. это еще и Плисы есть..fpga
“Железо” копеечное: клон платки ProMini с контроллером ATMega328 на борту и преобразователь USB-UART. А больше, пока, ничего не нужно:

все по программам есть на сайтах – electroda.pl qrz.ru radiokot.ru в поиске 12000 страниц похожих.
Данные часы без лишних функций, показывают только время и имеют будильник. В основе проекта микроконтроллер STM8Sx03. Чтобы каждый раз не пришлось устанавливать время после отключения источника питания, я применил микросхему RTC PCF8563 с питанием от батареи CR1220.
На плате установлен разъем microUSB для подключения основного источника питания 5В. Имеются две кнопки для установки времени и будильника. Удерживайте S1 для установки времени или S2 для установки будильника. Управление четырехразрядным семисегментным дисплеем осуществляется методом мультиплексирования, чтобы не превышать ток вывода контроллера.
Схема устройства

Благодаря уникальной функции часы имеют возможность отображать время вверх ногами, для этого просто удерживайте кнопку S1 при включении питания. Выбор будет сохранен в памяти контроллера. Кроме того, в версии v2 я добавил автоматическое определение типа дисплея (общий анод/катод), так что вы можете подключить любой. (это к светодиодным 7 сегментным восьмеркам относится. В газоразрядных каждый электрод это цифра целиком или точка . А вот управление можно со статической и с динамической индикацией так же).
Исходный код был написан на языке C.
Фото печатной платы

Видео работы устройства https://www.youtube.com/embed/tJPJDMM2t9o?rel=0&fs=1&wmode=transparent
Файлы к статье “Простые часы с будильником на STM8Sx03” | |
Описание: Файл прошивки микроконтроллера | |
Размер файла: 2.78 KB Количество загрузок: 144 | Скачать |
это на светодиодных восьмерках конечно – как флешка ставится в usb порт. для ламп nixie tube в прошивке порядочно всего менять.
esp8266 – первый раз был вариант 5 лет назад. от wi-fi берет с интернета время. сейчас на 4g 5g пора переводить – даже на тульских озерах уверенная связь была в этом году. Интересен более новым процессором на 160 мгц – можно пробовать майнить, в сеть он выходит, памяти только маловато.
Часы под управлением ESP8266

Автор: RoboC
Лампа: ИН-12 Схема: есть ( ESP8266 / ESP-12) Плата:есть (Sprint-Layout 6) Прошивка:не требуется Исходник:есть (Arduino) Описание: eсть Особенности: статическая индикация,ночной режим.
Схема:
Основой часов служит модуль ESP-12(WiFi) с чипом ESP8266 китайской компании Espressif. Пожалуй, радиолюбитель у которого есть интернет, уже знает или хотя бы слышал об этих модулях. Останавливаться на описании смысла нет.
Устройство ориентировано на повторение новичками(:). Исходя из этого, платы не сложные, сделаны по «ЛУТ» технологии, программатор не требуется (модуль программируется через COM-порт или переходник USB -RS232, с выходом 3.3V), средой программирования выбрана Arduino IDE. На платах есть напряжение опасное для жизни! Так будут выглядеть часы без корпуса после сборки:



Программа умеет:
- связываться с NTP сервером и получать от него точное время (раз в сутки);
- считать время между сеансами связи;
- синяя подсветка, которую можно включить и отключить;
- статическая индикация;
- Ночной режим (по времени).
https://www.youtube.com/embed/xjA7IPq3d8A?feature=player_detailpage
Часы – участник конкурса “Поздравь Кота по-человечески 2015”. Заняли 13 место :).
О сборке и настройке почитать можно на РАДИОКОТЕ по этой ссылке.
Файл прошивки от leoz с добавленным перебором цифр.
Фото не вошедшие в статью:






Вариант часов от uldemir
Правда, немного изменил схему. Взамен толпы 595-х регистров и ULN поставил одну HV5622, вместо преобразователя RS232-TTL3.3 поставил FTDI232BL. Ну и высоковольтный преобразователь сделал на IR2153. Ну и, конечно, всякие подсветки делать не стал. Как и выключение анодного (оставил потенциальную возможность использовать сигнал BLANK супертекса.)



Upd 2016/09/11 :
Вариант часов от Gramafon (РадиоКот) на ИН-14.



Прошивка для этих ламп (модифицированный leoz) и сами платы.
P.S. Я настоятельно советую ставить вместо 1117(линейника) , DC-DC
** я тоже уже менял на одной плате
Автор: RoboC на 13:21Отправить по электронной почтеНаписать об этом в блогеОпубликовать в TwitterОпубликовать в FacebookПоделиться в Pinterest Ярлыки: 4 лампы, ИН-12, Схема, часы, ESP8266, nixie, NTP, RoboC
ARM stm32 еще вариант
Часы-термометр на STM32F1

Автор: KT3012
Лампа:ИН-12 Схема: есть (STM32F1) Плата:есть Прошивка:есть Исходник:eсть Описание: естьОсобенности:первый девайс здесь на ARM.
Схема:


Генератор высокого напряжения для ин-ок выполнен на дросселе, диоде и транзисторе, где задает частоту микроконтроллер. Это избавило от дополнительной микросхемы и уменьшило сложность, но добавило проблем с настройкой (подбор частоты, необходимость в прошитом и работающем МК для проверки работы). Из-за этого произошла проблема – неудачно выбрал режим, на преобразователе напряжение стало свыше 300 вольт, из-за этого пробило ключевой транзистор, а через него достало до МК STM32F100C4, который изначально был припаян ( Так что имейте ввиду, подбор частоты лучше вести с самых малых значений, постепенно повышая.
Схема высоковольтных ключей типичная, там ничего нового, хотя в следующий раз лучше будет применить оптоключи, компактнее, безопаснее и проще. В анодах ламп стоят токоограничительные резисторы, их придется подбирать, дело в том, что у ламп могут быть разные рабочие характеристики (напряжение зажигания, изношенность). Следует избегать режима, при котором видно синеватое свечение в лампе, есть мнение, что это разрушаются электроды. Общий ток потребления всего устройства в целом около 80-120 мА.
На плате индикации расположены собственно лампы, кнопки управления, разъем для пищалки будильника, регистры и высоковольтные коммутаторы и транзисторы и схема генератора высокого напряжения. Диоды любые, у меня D6 (по схеме) это IN4007, D7 это стабилитрон на 50 вольт, я его не устанавливал, работает и так(от меня: полярность на схеме указана не верно и лучше поставить его вольт так на 27-30,от греха подальше).
Выходной транзистор 13005, остальные MMBTA42 и MMBTA92. Нижние ключи — сборки ULN2003. Из задействованных ресурсов МК используется:
— ШИМ таймера 2
— RTC
— АЦП
— I2C/UART
— Выводы и прочее
— резонатор поставил внешний кварцевый, хотя схема может вполне нормально и без него работать, вот, но необходимо тогда будет изменить в проекте константу частоты.
Детали для высоковольтной части (транзистор, дроссель) взяты из электронного балласта энергосебрегайки.
ЧТО лучше всего улучшить — переделать код на что-то более полезное, подсветка ламп светодиодиками не используется, можно добавить попсовые голубые светодиоды, доделать будильник, сделать что-то с UART-ом, например сделать на нем сеть из DS18B20 или просто сеть.
В прикрепленных файлах внизу схема и исходники. Недочеты (они везде есть, тем более у меня) исправлю позже.
Архив: первый и второй.
Первоисточник.
Автор: RoboC на 19:20Отправить по электронной почтеНаписать об этом в блогеОпубликовать в TwitterОпубликовать в FacebookПоделиться в Pinterest Ярлыки: 4 лампы, ИН-12, Часы-термометр, nixie, STM32F1
програмка от ардуино nixie3 . Это как пример – нужна библиотека two Wire и все. Адрес i2c задается в 7 строке, A4 A5 к модулю sdi scl. ниже будет.
https://pastebin.com/3f6q0eMh https://mysku.ru/blog/aliexpress/38444.html
#include <Shifter.h> #include <Wire.h> // Comes with Arduino IDE #include <Bounce.h> #define SER_Pin 3 //SER_IN DS #define RCLK_Pin 4 //L_CLOCK ST #define SRCLK_Pin 2 //CLOCK SH #define NUM_REGISTERS 8 //how many registers are in the chain #define DS3231_I2C_ADDRESS 0x68 bool dot = LOW; bool led = HIGH; #define BUTTON1 7 #define BUTTON2 13 #define BUTTON3 12 #define BUTTON4 11 #define BUTTON5 8 Bounce bouncer1 = Bounce(BUTTON1,10); Bounce bouncer2 = Bounce(BUTTON2,10); Bounce bouncer3 = Bounce(BUTTON3,10); Bounce bouncer4 = Bounce(BUTTON4,10); Bounce bouncer5 = Bounce(BUTTON5,10); //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); unsigned long timed; unsigned long timet; unsigned long curtimed; unsigned long curtimet; void setup() { Wire.begin(); timet = millis(); shifter.clear(); shifter.write(); pinMode(BUTTON1,INPUT); pinMode(BUTTON2,INPUT); pinMode(BUTTON3,INPUT); pinMode(BUTTON4,INPUT); pinMode(BUTTON5,INPUT); } void loop() { //set hours if ( bouncer1.update() ) { //if read high if ( bouncer1.read() == HIGH) { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); if (hour == 23){hour=-1;} setDS3231time(second, minute, hour+1, dayOfWeek, dayOfMonth, month, year); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); delay(100); } } //set minutes (+1) if ( bouncer2.update() ) { //if read high if ( bouncer2.read() == HIGH) { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); if (minute == 59){minute=-1;} setDS3231time(second, minute+1, hour, dayOfWeek, dayOfMonth, month, year); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); delay(100); } } //set minutes (-1) if ( bouncer3.update() ) { //if read high if ( bouncer3.read() == HIGH) { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); if (minute == 0){minute=60;} setDS3231time(second, minute-1, hour, dayOfWeek, dayOfMonth, month, year); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); delay(100); } } //null seconds if ( bouncer4.update() ) { //if read high if ( bouncer4.read() == HIGH) { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); setDS3231time(0, minute, hour, dayOfWeek, dayOfMonth, month, year); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); delay(100); } } if ( bouncer5.update() ) { //if read high if ( bouncer5.read() == HIGH) { if ( led == LOW ) { led = HIGH; } else { led = LOW; } //digitalWrite(ledpin,led); } } curtimet = millis(); curtimed = millis(); if (abs(curtimed-timed) >= 500){ dot=!dot; shifter.clear(); shifter.setPin(60, dot); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); timed = millis(); } if (abs(curtimet-timet) >= 30000){ nixietrainer(); timet = millis(); } } void nixie (int n, int val) { switch (val) { case 0: shifter.setPin(n + 5, HIGH); break; case 1: shifter.setPin(n + 4, HIGH); break; case 2: shifter.setPin(n + 3, HIGH); break; case 3: shifter.setPin(n + 2, HIGH); break; case 4: shifter.setPin(n + 1, HIGH); break; case 5: shifter.setPin(n, HIGH); break; case 6: shifter.setPin(n + 9, HIGH); break; case 7: shifter.setPin(n + 8, HIGH); break; case 8: shifter.setPin(n + 7, HIGH); break; case 9: shifter.setPin(n + 6, HIGH); break; case 10: //off break; } } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (50, oness); nixie (40, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (30, onesm); nixie (20, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (10, onesh); nixie (0, tensh); } void displayTime() { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); prints(second); printm(minute); printh(hour); } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // sets time and date data to DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd(second)); // set seconds Wire.write(decToBcd(minute)); // set minutes Wire.write(decToBcd(hour)); // set hours Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd(month)); // set month Wire.write(decToBcd(year)); // set year (0 to 99) Wire.endTransmission(); } void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set DS3231 register pointer to 00h Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes of data from DS3231 starting from register 00h *second = bcdToDec(Wire.read() & 0x7f); *minute = bcdToDec(Wire.read()); *hour = bcdToDec(Wire.read() & 0x3f); *dayOfWeek = bcdToDec(Wire.read()); *dayOfMonth = bcdToDec(Wire.read()); *month = bcdToDec(Wire.read()); *year = bcdToDec(Wire.read()); } void nixietrainer() { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(250); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(250); shifter.clear(); shifter.write(); return; } // Convert decimal numbers to binary coded decimal byte decToBcd(byte val) { return ( (val / 10 * 16) + (val % 10) ); } // Convert binary coded decimal to normal decimal numbers byte bcdToDec(byte val) { return ( (val / 16 * 10) + (val % 16) ); }
// настройка - немножко отличается от той что у автора. // У нас будет 5 кнопок: +1 час, +1 минута, -1 минута, обнулить секунды, включатель подсветки. Подсветки //пока нет, так что в коде заглушка. #define BUTTON1 7 #define BUTTON2 13 #define BUTTON3 12 #define BUTTON4 11 //#define BUTTON5 8 Поскольку нам нужна отзывчивость на нажатие кнопок, delay() по возможности не используем. Будут два таймера по функции millis(). Первый обновляет время два раза в секунду и мигает разделительными индикаторами: if (abs(curtimed-timed) >= 500){ dot=!dot; shifter.clear(); shifter.setPin(60, dot); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); timed = millis(); } 0-59 выводы это у нас цифры в лампах, 60-й подключен к неонкам. Второй — скринсейвер против отравления в катодах. Раз в 30 секунд прогоняет все числа: if (abs(curtimet-timet) >= 30000){ nixietrainer(); timet = millis(); }
эта конструкция и вот еще на ин-18 https://github.com/tysch/STM32-Nixieберется как образец. 74hc595 еще добавляются регистры они управляются по spi. https://github.com/JassyL/STM32_74HC595_Driver . А вот на сами лампы uln2003. Хороший совет разобрать сгоревшие энергосберегайки на транзисторы. У меня будет проба тест на ИН-1 которые требуют 200 вольт а ключи uln2003 на 50 вольт. Исходники и прошивки смотрите а то вдруг там майнер и нехолосые часы сразу пшшш бух. * Французская книжка Гварески – Ацетилен, там 3-летний ребенок развлекался. Ну да на новых микроконтроллерах можно и биткоины считать.
вот еще прочитать – https://0x7d.com/2017/nixie-tube-clock там красивая картинка запуск ламп с разным током. Статическая индикация лучше конечно для нее сдвиговые регистры. Регистр принимает информацию по коду spi и запоминает ее сдвигая биты дальше на другие – там 2 штуки на лампу и всего 9 на 6 ламп. Сейчас будет фота – изготовление платы под ИН-1 6 штук и на ней же будут сдвиговые регистры и ключи на ULN2003 , припаяные сразу к лампам и к фольге которая заземление и общий провод.Кусочек платы это повышающий модуль на AIC1563CN = MC34063 чуть более мощный аналог от неисправного модема. Если что пойдет не так – разницы напряжения в 50 вольт не хватит, например будет неполное включение или засветки соседних цифр то сделаю ключи на 50 транзисторах можно оставив те же ULN2003 – в ней есть похоже ограничитель стабилитрон на 50 вольт (а может полевик). * по программам ниже кое что будет. Наверно остановлюсь на варианте который esp12 берет точное время с сети . Атомные часы точнее Но есть термостатированый кварц от частотомера он работает 30 лет уже не выключаясь. и есть конечно ds3231, выбор отставание в секунду за год или в 2 минуты или совсем точно, задержка сети полсекунды. Основная часть программы считать время и выгрузить на цепочку регистров по SPI – если включено питание то загораются цифры. *ULN2003 стоят на китайской плате – я нашел К155ИД1 а на декатроны в количестве 2 штук будет 74HC595D (spi) и к электродам катоду первому и второму КТ940А он держит 300 вольт этого вполне хватит (на аноде 420 у А101 и через резистор 500-1500К). примерная схема в виде модулей есть чуть ниже.
https://github.com/alexey-chernysh/74HC595
про индикаторы (meandr.ru ) здесь я не очень с этим согласен хоть и проще получается – иногда схему можно немножко усложнить если будет быстрее программа или потребует меньше места в памяти и можно перенести на более простой микрокомпьютер где меньше выводов . Напрашивается добавить 514ИД1 или 155 * .. 74hc141 К155 (555) 133ИД1 = (141) – декодер 4 в 10 для газоразрядных индикаторов или 1533ИД3 (155) декодер 4 бита в 16 , тоже подойдет подключить 10 электродов – цифр через транзисторную сборку.
Статическая индикация на семисегментниках с использованием 74hc595
источник Radioelektr.ru

Я думаю, у многих при использовании динамической индикации на семисегментных индикаторах возникали проблемы с яркостью индикаторов. А всё потому, что сегменты постоянно подключаются – отключаются и получается некое подобие ШИМ. Чтобы этого не происходило, следует использовать статическую индикацию. При таком принципе сегменты зажигаются один раз и переключаются только при изменении цифры. Это и программно удобно: не нужно постоянно вызывать из программы функции или подпрограммы, отвечающие за динамическую индикацию. Нужно только при изменении данных повторно вывести их на дисплей и всё.
Но возникает проблема: для этого нужно много выводов микроконтроллера. К примеру, если у нас 4 цифры, то нужно 8х4=32 вывода, у у Меги16 их всего 32. Поэтому для реализации статической индикации необходимо использовать сдвиговые регистры или расширители портов.
Расширители портов, как правило, подключаются к микроконтроллеру через SPI/I2C и представляют из себя полноценный порт ввода-вывода, который можно настроить на вход/выход и перевести в высокоомное Hi-Z сотояние(это когда вывод как-бы ни к чему не подключен).
А сдвиговые регистры(я рассматриваю именно 74hc595) дают нам совокупность ножек, которые являются выходами и их также можно перевести в состояние Hi-Z. Управляются они через последовательный интерфейс. В данном случае это подобие SPI. Конечно, существуют и регистры с параллельным входом – последовательным выходом и другие, но мы не будем их рассматривать в рамках данной статьи.
Как Вы уже догадались, для реализации статической индикации нам достаточно сдвиговых регистров. Наверное, самые популярные из них – 74hc595. Это регистры-защёлки с последовательным входом – параллельным выходом. Защёлками они называются потому, что после того, как мы запишем в них данные, их необходимо “защёлкнуть” – перевести на некоторое время состояние одного из пинов в логическую единицу. Только после этого будет изменено состояние выходов.
Вот распиновка регистра:
Распишу выводы по порядку:
- VCC и GND – питание, оно может быть в пределах от 2 до 6 Вольт.
- Qa – Qh – выходы регистра, каждый из них тянет до 6 мА тока при питании 5 Вольт.
- Qh’ – вывод для объединения нескольких регистров. Он подключается к входу данных следующего регистра, ещё расскажу об этом.
- SER – вход данных регистра.
- SRCLK – вход для тактовых импульсов.
- RCLK — Защелка. Подаём на него единицу и данные защёлкиваются.
- OE – Если подать на этот вывод 1, то выходы передут в высокоомное стостояние, если 0 – в рабочее сотояние(0 или 1).
- SRCLR – сброс регистра.
Для реализации статической индикации на понадобятся выводы питания, выходы регистра и выводы SER, SRCLK, RCLK. Если больше одного регистра – можно соединить их цепочкой: вывод Qh’ предыдущего регистра с выводом SER следующего. Вот общая схема включения(подтяжка RESET у МК не нарисована, но подразумевается; картинка кликабельна):
Порядок записи в регитр такой: сначала устанавливаем нужный уровель на SER, который должен соответствовать требуемому биту, потом устанавливаем в единицу SRCLK и потом сразу-же устанавливаем его в ноль. Произойдёт вывод 1 бита, следующий бит будет сдвигать предыдущий. Повторяем такой цикл 8 раз(или 32 раза с 4-мя разрядами индикатора), после всех действий устанавливаем в единицу защёлку, потом обнуляем, и данные будут обработына и выведены. Более подробно расписано в комментариях к коду примера. Скачать можно в конце статьи.
Для реализации статической индикации я написал неольшую библиотеку. Она изначально поддерживает Дисплей с 4-мя цифрами. При желании можете сократить/увеличить количество цифр. В комментариях к коду всё подробно расписано. Пользоваться библиотекой просто. Для начала добавьте файл 74hc595segment.asm в папку с проектом, подключите библиотеку к проекту где-нибудь в конце программы, там, где находятся подпрограммы :
#include "74hc595segment.asm"
После, там, где у Вас инициализация, добавьте строку с инициальзацией(скорее, настройкой портов):
rcall display_init
Дальше пропишите порты ввода-вывода, на которых будут висеть регистры, определения находятся в начале файла с библиотекой:
;========================================================================== ;Указываем выводы, на которых будет сидеть шина данных ;Сначала порты и DDR .equ DS_PORT = PORTA .equ DS_DDR = DDRA;Данные .equ TAKT_PORT = PORTA .equ TAKT_DDR = DDRA;Вход тактировки 74hc595 .equ ZAS_PORT = PORTA .equ ZAS_DDR = DDRA;Защёлка ;А дальше указываем конкретные выводы .equ ZAS = PA2; Защёлка .equ TAKT =PA1; Вход тактировки 74hc595 .equ DS = PA0; Данные ;=========================================================================
Теперь можно пользоваться. Загружем в переменные цифры и выводим их на дисплей:
ldi r16,1;Загружем цифорки в соответствующие ячейки памяти. sts digits,r16 ldi r16,2 sts digits 1,r16 ldi r16,3 sts digits 2,r16 ldi r16,4 sts digits 3,r16 ldi r16,0b00001000; Установка точки. sts digits 4,r16 ;Младшие 4 бита соответствуют четырём точкам(слева-направо). rcall display;Выводим на дисплей данные
Полный текст программы:
;========================================================================
;Тестовая программа для проверки библитеки, предназначеной ;Для реализации статической индикации на семисегментниках с ;Использованием сдвиговых регистров 74hc595
; ©LPA, 2012 ; http://radioelektr.ru ;========================================================================
.include "m16Adef.inc" ;=========================================================================
ldi r16,low(ramend)
out spl,r16
ldi r16,high(ramend)
out sph,r16 ;Стек
rcall display_init
;Настройка портов ввода-вывода, к которым подключены регистры ;============================
=============================================
ldi r16,1;Загружем цифорки в соответствующие ячейки памяти. sts digits,r16
ldi r16,2
sts digits 1,r16
ldi r16,3
sts digits 2,r16
ldi r16,4
sts digits 3,r16
ldi r16,0b00001000; Установка точки.
sts digits 4,r16 ;Младшие 4 бита соответствуют четырём точкам(слева-направо).
rcall display;Выводим на дисплей данные
main:
;Главный цикл пуст
rjmp main ;=========================================================================
.include "74hc595segment.asm";Подключение библиотеки
[/code]
А вот что из этого получилось:
zzz
Если хотите изменить библиотеку под свои индикаторы – никаких проблем, в конце библиотеки есть таблица символов. Её можно расширить, сократить, можно задать состояние каждого вывода регистра для определённой цифры. Код прокомментирован, поятому, я думаю, проблем не будет.
Также я сделал ещё один пример: простые часы с использованием статической индикации и DS1307. В симуляторе они выглядят так:
В архиве есть две прошивки с исходниками и модели в протеусе(v 7.7 SP2). Исходники прокомментированы.
Удачи!
Скачать библиотеку для статической индикации и примеры
radioelektr.ru meandr.org
- вот почти такая же конструкция (уже 101-я). 2011 год. Особенности – статическая индикация, просто кристалл atmega328p , а у меня 6 штук ИД1, обойдусь без транзисторов. ( может поставлю для усиления диодики к +60 вольтам как в uln2003).
- вот еще – 4 лампы esp8266 74hc595 uln2003 код ардуино включает электроды напрямую без дешифратора ИД1.
(это восстановление электродов – не надо так делать, вручную взять с анода декатрона 450 вольт с изолентой! резистор 500 килоом 2 ватта к аноду и ко всем лапкам соединить проволочку к минусу. )
На картинке перебор. Если пропечь так, то потом и ножка будет светиться в нормальном режиме. Укручиваем ток, чтобы горело только то, что нужно, и оставляем. До готовности.
Потом всё работает нормально и на штатном токе.

Кстати, покрытие пришлось смыть. Оно было потертое жизнью. Жаль, но и оставлять не комильфо.
Хотя бы снимается оно просто: отмачиваем лампочки в теплой воде с Фейри, потом пленка облазит или сама, или с легкой помощью какого-нибудь скребка.
Поздравляю, Вы собрали железо. Осталось только написать скетч для Ардуины (ну и сделать винтажный деревянный корпус, конечно же).
Кодинг
Сразу пардон, погромист я еще в меньшей степени, чем железячник.
Возможно, в коде будут костыли и велосипеды.
Но работает же!
Я нашел удобную библиотеку для Arduino: bildr.org/2011/08/74hc595-breakout-arduino/
Скачать
Суть в том, что она упрощает работу со сдвиговыми регистрами совсем до безобразия, позволяя управлять каждым выводом так, будто это цифровой пин Ардуины.
Кнопки настройки часов нужно защитить от дребезга. Вот описание проблемы: greenoakst.blogspot.cz/2012/06/arduino-bounce.html
Будем делать, как советует автор, с библиотекой Bounce. Скачать
Ну и наконец, мой скетч: скачать вложение. nixie3 внизу во вложении и код чуть выше
Пояснения по коду У нас будет 5 кнопок: +1 час, +1 минута, -1 минута, обнулить секунды, включатель подсветки. Подсветки пока нет, так что в коде заглушка.ссылка – https://yahobby.ru/webdirectory/82841/%d1%80%d0%b5%d0%b3%d0%b8%d1%81%d1%82%d1%80-74hc595-%d0%b8-%d0%b5%d0%b3%d0%be-%d1%81%d0%b2%d1%8f%d0%b7%d0%ba%d0%b0-%d1%81-%d0%b0%d1%80%d0%b4%d1%83%d0%b8%d0%bd%d0%be/ это на 74hc595 че то блокировки сайтов достали..
//кнопики для установки времени на какой вывод ардуино
#define BUTTON1 7
#define BUTTON2 13
#define BUTTON3 12
#define BUTTON4 11
#define BUTTON5 8
а другой вариант 3 кнопки на одном аналоговом выводе - одна замыкает накоротко, вторая через 30к и третья через 3к. будет в еще одной программе.
яя
Поскольку нам нужна отзывчивость на нажатие кнопок, delay() по возможности не используем. Будут два таймера по функции millis(). Первый обновляет время два раза в секунду и мигает разделительными индикаторами:
if (abs(curtimed-timed) >= 500){ dot=!dot; shifter.clear(); shifter.setPin(60, dot); displayTime(); // display the real-time clock data on the Serial Monitor, shifter.write(); timed = millis(); }
c ++ asm
0-59 выводы это у нас цифры в лампах, 60-й подключен к неонкам.
- я еще сюда подключу декатрон – с управлением через 4 транзистора (есть готовый Ардуино Шилд, только его доделаю, там из тонкостей надо напряжения разные – для сброса , переноса разряда, включения , 300 вольт, 450 анод, 60 и 30 вольт или -10).
Второй — скринсейвер против отравления в катодах. Раз в 30 секунд прогоняет все числа:
if (abs(curtimet-timet) >= 30000){
nixietrainer();
timet = millis(); }
В остальном, ничего интересного. Надергано с примеров по подключению часов, и так далее.
Чего непонятно — спрашивайте.
Ну, готово!
Часики вышли здоровые, мои предыдущие раза в полтора меньше их смотрятся.
Конечно, работы еще много: подсветка, корпус, кнопки, но уже можно поставить на подоконник в ожидании доделки.


https://github.com/santosha2003/74HC595 связка stm8 с регистром. * а кроме регистров есть еще и ОЗУ – а это что и чем отличается – а там не один байтик хранится а несколько , 4096 например а зачем и как – придумаем ( разговор караульных на посту в 1986, один потом сделал фирму по созданию сайтов и что то с майнингом, второй в Китае в Шеньжень).Оттуда миллионов 20 игровых приставок – до сих пор делают и не так дорого как плейстейшн.
почти пошаговая инструкция.
это не сложно – девушка в 13 лет сама распаяла набор часов из Китая, правда она увлекающаяся. Основная сложность у начинающих – определить какие детали полярные например светодиод и какой стороной ставить на плату если не однозначно, прочитать инструкцию и потихоньку схему, найти соответствие на плате. Научиться паять с канифолью а не просто подавая пруточек припоя из катушки, это немножко искусство, вот в Китае зря одним словом называют и пайку и сварку, правда другим словом иероглифом сразу уточнение.
А вот и с дешифратором -не если их найду – ну не в Минск же за ними ехать 🙂 можно и на 1533ИД3 и на транзисторах или сборках uln2003 подключить лампы – усложнение конечно . К155ИД1 выдерживает 310 вольт * там есть внутри стабилитрон на 60 вольт, если смотреть по схеме включения, хотя там реально напряжение в несколько раз ниже, на ULN2003g замерял 50 вольт. hv5622 тоже подходит.. ну на 5 долларов горсть микросхем ULN2003G и 74НС595 . С пайкой проводов затруднение – в советское время еще придумано решение для таких макеток , чтобы каждый раз платы не разводить и при каждой переделке опять.. нет не накрутка, это только для квадратных выводов специально под нее сделаных годится, обжигалка из резистора в зеленом корпусе из керамики покрытой стеклом, наполненным оловом и тонкий провод во фторпластовой изоляции. А там у них придумали FlyWire это еще и красиво. *нашел 70 рублей .
схема статической индикации – то есть пока в регистры новые данные не запишутся, включены постоянно цифры. Динамическая проще. Раз в минуту обязательно антиотравление, 75 килоом к высокому напряжению подобрать – может побольше можно, снизит ток через лампы.

от программы зависит как и соединения. или наоборот, поправка в программе под готовую плату. на flywire ну да летящим проводом – пониже – там правильнее (перебросить если что провода в соответствии с кодом цифр)

настройка блока питания dc-dc – у меня батарея 3s18p Один виток выдает 5в если холостой ход, на декатроне то есть на емкости перед резистором 560 вольт, разряд на декатроне горит. На отводе ровно 200 вольт, потребление 1.2 ватта. Подключаю микросхемы – просадка до 3.8 вольта. Более толстый провод не влезет, да и ток всего до 600 ма, 6 штук ИД1 и 3 74 hc 590. Попробую в работе от 3.8 ну от 4 вольт, вроде как работать будет. Ардуинка запускается. 2 витка дают 6 вольт и потребление сразу 3 ватта, это вообще перебор – нагреется все. Лучше 4 вольта оставлю или все таки 7805 добавить или – диодик кд213, на нем как раз 1.2 вольта падение, а на шоттки всего 0.4 при этом токе.
нижний модуль по схеме – можно приспособить на подключение декатрона – те же транзисторы КТ940А они до 300 вольт. На декатроне секунды или эффект заполнения или маятник.
http://download.elektronicastynus.be/57/IN-14.htm 6 ламп с секундами, тоже подключены через 74hc595, 3 по цепочке и через 6 штук 74141, PIC 16F628a. DS18b20 Время считывается по one_wire , регистры по i2c . Полундра! надо код с голландского переводить – месяц год число и все цифры.
// коды цифр которые пишутся в 74hc595 и подаются на 155ИД1 74141 подобрать
' pic basic
'****************************************************************
'* Name : IN-14 Nixie klok *
'* Author : Stijn Coenen [Stynus] www.ElektronicaStynus.Be *
'* Notice : Licenced under Creative Commons *
'* : Attribution-Noncommercial 2.0 Belgium Licence *
'* : http://creativecommons.org/licenses/by-nc/2.0/be/ *
'* Date : 6/03/2010 *
'* Version : 1.0 *
'****************************************************************
Device 16F628A
Config INTRC_OSC_NOCLKOUT, WDT_off, PWRTE_ON, LVP_off, MCLRE_OFF, BOREN_OFF
All_Digital TRUE
'****************************************************************
'In en uitgangen
'Nixies en neons
Symbol klok = PORTB.6
Symbol ZetVast = PORTB.5
Symbol Data_Pin = PORTB.4
'RTC
Symbol SDA = PORTA.3
Symbol SLC = PORTA.2
'Temperatuursensor
Symbol one_wire = PORTA.4
'Knoppen
Symbol KnopL = PORTA.1 : TRISA.1 = 1
Symbol KnopM = PORTA.0 : TRISA.0 = 1
Symbol KnopR = PORTA.7 : TRISA.7 = 1
'Leds
Symbol LedT = PORTB.3 : TRISB.3 = 0
Symbol LedD = PORTB.1 : TRISB.1 = 0
Symbol LedU = PORTB.0 : TRISB.0 = 0
'****************************************************************
Dim Seconden As Byte
Dim Minuten As Byte
Dim Uren As Byte
Dim Datum As Byte
Dim Maand As Byte
Dim Jaar As Byte
Dim Temperatuur As Byte
Dim TemperatuurW As Word
'************************************************************
'Subroutine variable
Dim temp As Byte
Dim getal As Byte
Dim ZetOm As Byte
Dim y As Byte
Dim tot As Byte
'************************************************************
Dim index As Byte
Dim digit1 As Byte
Dim digit2 As Byte
'************************************************************
'De nixie aansluitingen zitten niet op de normale plaatsen van
'de driver ic om plaats te besparen, daarom geef ik aliassen
'aan de cijfers die overeenkomen met de bcd code van dat cijfer
'op mijn print
'The nixie connections are not on the normal positions off the
'driver ic. I did this to safe some space on the PCB. On the
'following piece of code I'm giving aliases to the Dutch name
'of the numbers that represent the bcd code from the digit on
'my pcb
Symbol Nul = %00000001
Symbol Een = %00001100
Symbol Twee = %00000100
Symbol Drie = %00001001
Symbol Vier = %00000000
Symbol Vijf = %00001000
Symbol Zes = %00000010
Symbol Zeven = %00001011
Symbol Acht = %00001010
Symbol Negen = %00000011
'************************************************************
'Aliassen voor de registers in de RTC
'Aliases for the registers in the RTC
Symbol Reg_Seconden = $00
Symbol Reg_Minuten = $01
Symbol Reg_Uren = $02
Symbol Reg_Dag = $03
Symbol Reg_Datum = $04
Symbol Reg_Maand = $05
Symbol Reg_Jaar = $06
'Controle bytes RTC
Symbol Lezen = %11010001 'Read
Symbol Schrijven = %11010000 'Write
'****************************************************************
Clear
GoTo OverSub
'****************************************************************
'Sub routines
'************************************************************
'Deze subroutine zet een BCD getal om in een BCD getal dat
'overeenkomt met de aansluitingen ven de nixies op de driver ic's
'This subroutine changes a BCD number in to another BCD number
'that represents the connections of the nixie on the driver ic's
Omzetten:
'De 4 laagste bits uit getal halen
'Get the lower 4 bits out of getal
getal = ZetOm & %00001111
'De nieuwe bcd waarde voor dat getal opzoeken
'Get the new bcd value for that number
Select getal
Case 0
getal = Nul
Case 1
getal = Een
Case 2
getal = Twee
Case 3
getal = Drie
Case 4
getal = Vier
Case 5
getal = Vijf
Case 6
getal = Zes
Case 7
getal = Zeven
Case 8
getal = Acht
Case 9
getal = Negen
Case Else
getal = %00001111 'Uit
EndSelect
'De 4 laagste bits in getal 4 plaatsen naar links opschuiven (De nixie drivers
'hangen omgekeerd op de 74HC595 ic's.) Daarna in temp zetten
'Put the 4 lowest bits in getal 4 places to the left. (The nixie drivers are
'reversed connected to the 74HC595 ic's.) Then put it in temp
temp = getal << 4
'Tientallen
'De 4 hoogste bits uit getal halen
'Get the higher 4 bits out of getal
getal = ZetOm & %11110000
getal = getal >> 4
'De nieuwe bcd waarde voor dat getal opzoeken
'Get the new bcd value for that number
Select getal
Case 0
getal = Nul
Case 1
getal = Een
Case 2
getal = Twee
Case 3
getal = Drie
Case 4
getal = Vier
Case 5
getal = Vijf
Case 6
getal = Zes
Case 7
getal = Zeven
Case 8
getal = Acht
Case 9
getal = Negen
Case Else
getal = %00001111 'Uit
EndSelect
ZetOm = temp + getal
Return
'************************************************************
UrenUit:
SHOut Data_Pin, klok, msbfirst, [Uren \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [Minuten \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [Seconden \ 8]
High ZetVast
DelayUS 20
Low ZetVast
Return
'************************************************************
DatumUit:
SHOut Data_Pin, klok, msbfirst, [Datum \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [Maand \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [Jaar \ 8]
High ZetVast
DelayUS 20
Low ZetVast
Return
'************************************************************
TempUit:
SHOut Data_Pin, klok, msbfirst, [%11111111 \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [Temperatuur \ 8]
DelayUS 20
SHOut Data_Pin, klok, msbfirst, [%11111111 \ 8]
High ZetVast
DelayUS 20
Low ZetVast
Return
'************************************************************
TijdInst:
y = 0
'In deze subroutine blijven voor 7.5 sec nadat de laatste
'knop is ingedrukt
'Stay in this sub for 7.5 seconds after the last button
'is pressed
While y < 50
'Tijd inlezen
'Read time
I2CIN SDA, SLC, Lezen, Reg_Uren, [Uren]
I2CIN SDA, SLC, Lezen, Reg_Minuten, [Minuten]
I2CIN SDA, SLC, Lezen, Reg_Seconden, [Seconden]
Inc y
If KnopR = 0 Then
'De maximimale waarde dat de seconde variabele mag
'worden instellen op 59
'Set the max value that the variable may become on 59
tot = 0x59
'1 optellen in de sub BCD_Plus
'Ad 1 in the sub BCD_Plus
getal = Seconden
GoSub BCD_Plus
Seconden = getal
'Waarde wegschrijven naar de RTC
'Write the value to the RTC
I2COUT SDA, SLC, Schrijven ,Reg_Seconden, [Seconden]
'Teller om in de sub te blijven resetten
'Reset the counter to stay in this sub
y = 0
EndIf
If KnopM = 0 Then
tot = 0x59
getal = Minuten
GoSub BCD_Plus
Minuten = getal
I2COUT SDA, SLC, Schrijven ,Reg_Minuten, [Minuten]
y = 0
EndIf
If KnopL = 0 Then
tot = 0x24
getal = Uren
GoSub BCD_Plus
Uren = getal
I2COUT SDA, SLC, Schrijven ,Reg_Uren, [Uren]
y = 0
EndIf
'De waardes op de nixies zetten
'Put the value's on the nixies
ZetOm = Uren : GoSub Omzetten : Uren = ZetOm
ZetOm = Minuten : GoSub Omzetten : Minuten = ZetOm
ZetOm = Seconden : GoSub Omzetten : Seconden = ZetOm
GoSub UrenUit
DelayMS 150
Wend
Return
'************************************************************
DatumInst:
y = 0
'In deze subroutine blijven voor 7.5 sec nadat de laatste
'knop is ingedrukt
'Stay in this sub for 7.5 seconds after the last button
'is pressed
While y < 50
'Tijd inlezen
'Read time
I2CIN SDA, SLC, Lezen, Reg_Jaar, [Jaar]
I2CIN SDA, SLC, Lezen, Reg_Maand, [Maand]
I2CIN SDA, SLC, Lezen, Reg_Datum, [Datum]
Inc y
If KnopR = 0 Then
tot = 0x99
getal = Jaar
GoSub BCD_Plus
Jaar = getal
I2COUT SDA, SLC, Schrijven ,Reg_Jaar, [Jaar]
y = 0
EndIf
If KnopM = 0 Then
tot = 0x12
getal = Maand
GoSub BCD_Plus
Maand = getal
I2COUT SDA, SLC, Schrijven ,Reg_Maand, [Maand]
y = 0
EndIf
If KnopL = 0 Then
tot = 0x31
getal = Datum
GoSub BCD_Plus
Datum = getal
I2COUT SDA, SLC, Schrijven ,Reg_Datum, [Datum]
y = 0
EndIf
'De waardes op de nixies zetten
'Put the value's on the nixies
ZetOm = Jaar : GoSub Omzetten : Jaar = ZetOm
ZetOm = Maand : GoSub Omzetten : Maand = ZetOm
ZetOm = Datum : GoSub Omzetten : Datum = ZetOm
GoSub DatumUit
DelayMS 150
Wend
Return
'************************************************************
BCD_Plus:
temp = getal & %00001111
Inc temp
If temp = 10 Then
temp = 0
temp = getal & %11110000
temp = temp >> 4
Inc temp
If temp = 10 Then
getal = 0
Else
getal = temp << 4
EndIf
Else
getal = getal & %11110000
getal = getal + temp
EndIf
If getal > tot Then
getal = 0
EndIf
Return
'************************************************************
OverSub:
'Start Temperature sensor
'Zend 'Convert' opdracht (temperatuur meten)
'Send 'Convert' command (measure temperatuur)
OWrite one_wire, 1, [$CC, $44] ;
'Zend 'Read ScratchPad' opdracht (zend temperatuurmeting)
'Send 'Read ScratchPad' command (send temperatuurmeasurement)
OWrite one_wire, 1, [$CC, $BE] ;Zend '' opdracht
ORead one_wire, 2, [TemperatuurW.LowByte, TemperatuurW.HighByte]
'****************************************************************
Main:
While 1 = 1
'************************************************************
'Tijd weergeven
'Display time
High LedU
For index = 0 To 100
'Tijd inlezen
'Read time
I2CIN SDA, SLC, Lezen, Reg_Uren, [Uren]
I2CIN SDA, SLC, Lezen, Reg_Minuten, [Minuten]
I2CIN SDA, SLC, Lezen, Reg_Seconden, [Seconden]
'Knop ingedrukt? -> sub TijdInst
'Button pressed? -> sub TijdInst
If KnopR = 0 Or KnopM = 0 Or KnopL = 0 Then
GoSub TijdInst
EndIf
'De waardes op de nixies zetten
'Put the value's on the nixies
ZetOm = Uren : GoSub Omzetten : Uren = ZetOm
ZetOm = Minuten : GoSub Omzetten : Minuten = ZetOm
ZetOm = Seconden : GoSub Omzetten : Seconden = ZetOm
GoSub UrenUit
DelayMS 100
Next
Low LedU
'************************************************************
'Datum weergeven
'Display date
High LedD
For index = 0 To 30
'Datum inlezen
'Read date
I2CIN SDA, SLC, Lezen, Reg_Jaar, [Jaar]
I2CIN SDA, SLC, Lezen, Reg_Maand, [Maand]
I2CIN SDA, SLC, Lezen, Reg_Datum, [Datum]
'Knop ingedrukt? -> sub TijdInst
'Button pressed? -> sub TijdInst
If KnopR = 0 Or KnopM = 0 Or KnopL = 0 Then
GoSub DatumInst
EndIf
'De waardes op de nixies zetten
'Put the value's on the nixies
ZetOm = Jaar : GoSub Omzetten : Jaar = ZetOm
ZetOm = Maand : GoSub Omzetten : Maand = ZetOm
ZetOm = Datum : GoSub Omzetten : Datum = ZetOm
GoSub DatumUit
DelayMS 100
Next
Low LedD
'************************************************************
'Temperatuur weergeven
'Display temperature
High LedT
'********
'DS18B20 inlezen || Read DS18B20
'Code van Reddevil || Code by Reddevil
'http://www.schematheek.net/index.php?p=forum/topic&t=297&n=1#3218
'Zend 'Convert' opdracht (temperatuur meten)
'Send 'Convert' command (measure temperatuur)
OWrite one_wire, 1, [$CC, $44] ;
'Zend 'Read ScratchPad' opdracht (zend temperatuurmeting)
'Send 'Read ScratchPad' command (send temperatuurmeasurement)
OWrite one_wire, 1, [$CC, $BE] ;Zend '' opdracht
ORead one_wire, 2, [TemperatuurW.LowByte, TemperatuurW.HighByte]
'4 plaatsen opschuiven voor getal naar de comma weg te gooien
'Shift 4 places to dispose the value after the decimal separator
TemperatuurW = TemperatuurW >> 4
'********
'Temperatuur in een bcd waarde opzetten
'Convert the temperature in a bcd value
digit1 = Dig TemperatuurW, 1
digit2 = Dig TemperatuurW, 0
digit1 = digit1 << 4
Temperatuur = digit1 + digit2
ZetOm = Temperatuur
GoSub Omzetten
Temperatuur = ZetOm
'Temperatuurmeting zit niet in een lus om te voorkomen dat
'de temperatuursensor gaat opwarmen door hem teveel uit te
'lezen
'The temperatuurmeasurement is not in a loop, to avoid
'heating up the sensor trough reading it to mutch
GoSub TempUit
DelayMS 3000
Low LedT
'************************************************************
Wend
'****************************************************************
End
в часах на ИН-1 ИН1 А101 надо 4 регистра по цепочке. в первые 3 загружаются цифры для 6 штук ин1 то есть час минуты секунды а в четвертый управление декатроном – байты по таблице. Индикаторы как бы в статике, но в регистры информация может довольно часто записываться, напишу как быстро справляется процессор. Декатрон с синим огоньком считает до миллиона в секунду, а тот что проверялся на видео от катушки Теслы – до 1000 импульсов в секунду, он с оранжево – красным разрядом, коммутаторный еще. Может и отдельный и даже со своим миктоконтроллером или ардуино – коммутаторные декатроны удалось купить они не только умеют сосчитать импульсы а еще переключают если надо что нибудь – светодиоды через транзистор, еще один газоразрядный индикатор – только сопротивления надо. На коммутаторном декатроне есть (советские патенты) скоростное управление техникой точечной сваркой например, станком, какой то автоматической линией. В сети есть полностью ламповая конструкция, ну это конечно с чемодан размером и киловатт потребляемая мощность. А выглядит красиво. на этой или следущей странице arduino decatron shield * сейчас на декатроне бегает просто пружинка Слинки.
К155ИД1 5- питание 5в, 12 общий –

К155ИД1 – на верхней схеме неправильно помечены инверсными входы 1 2 4 8, а выходы правильно, активный сигнал идет нулевым уровнем, а выключены остальные выходы . Есть таблица состояний – если все 4 входа 0 то на 16 лапе выход 0 вольт, остальные отключены, на индикаторе горит 0 подсоединенный к 16 выводу. Отключенные выдерживают 60 вольт, но рассчитаны на небольшой ток, только на цифровой индикатор газового разряда – при этом режиме разряд неонки не горит и ток через внутренний стабилитрон не идет, так же и если ставить uln2003, только там 50 вольт. (выходы транзисторной сборки и ИД1 почти одинаковы.) Если применять лампы ИН-1 и питание 200 вольт то лучше ставить К155ИД1. Если 170 вольт как на китайской плате то можно ИН-1 тоже но лучше ИН14 ИН16 у них меньше напряжение зажигания.
155 ид 1 выпускает з-д Интеграл и сейчас тоже 2020-08 . 6 дешифраторов не дороже hv5622. Так чо эта схема выше неплохой вариант, на нем и . останавливаюсь. Так не переписывать программу если секунды будут на зеленых лампах ИВ-22 ! просто 1 модуль другой. Вместо 155ИД1 будет на секундные цифры К514ИД1 и по 7 транзисторов, они 7-сегментные. *А можно и вообще без всяких микроконтроллеров сделать – в основе будет опять эта схема , только HC595 тогда не очень нужна будет – скорее потребуется другой регистр защелка ИР23 (323).

ИН-1 из коробочки новые 1991 а ИН-16 маленькая 1974 года снята откуда то из кассы наверно – работает. ИН 1 вообще разношерстные одна МЭЛЗ 1966, у нее мелкая сетка, остальные Анод – эмблемки в виде спирали лампочки и электрод со стрелочкой а может и еще чего на эмблемке завода.

Она на секунды будет – я считаю часы без секунд это не то, хотя можно секунды на декатроне! * Совет по проверке – поднести лампочку к маленькой катушке Теслы, только чтобы по стеклу искры долго не шпарили. На расстоянии 20-30 сантиметров она вспыхнет оранжевым, при этом может конечно слегка обжечь пальцы, ну можно взять лампочку кусочком фольги и даже заземлить ее проводком, фольгу. Интересный эффект у ламп ИН-14 ИН16 Ин-8 ИН-12 А102 ОГ-7 – вспыхивают голубым на высокой частоте а потом только оранжевым. Значит там разные газы в смеси, аргон водород а может ртуть кроме неона. МТХ-90 ИН-3 вспыхивают оранжевым – неон. Стабилитрон СГ-302С голубой точкой -водород. Плохие лампочки не загораются.
Все неонки проверяются (кроме самой мощной которая выглядит как 60-ваттная обычная лампа. Продам такую коллекционеру она 1951 года, за 5 тысяч долларов начальная цена.) просто подсоединив в розетку 220 вольт через резистор 300 – 500 килоом обязательно, большой 2 ватта. Напрямую она конечно разрушится.
На этой же плате со стороны фольги ставятся маленькие плоские 74HC595 всего 4 штуки – в них то будет защелкиваться 8 бит информации в коде шестнадцатеричном, 1-2-4-8 а в четвертом точки если поставлю на неонках и можно подсветку, четвертый дополнительно надо 3 на 6 ламп. Четвертый на декатрон и его *драйвер. После дешифраторов – например если передать 0x8 и 0x1 в первый регистр загорятся цифры 1 8 , просто цифры с 1 по 9 они и в шестнадцатеричном так же.

У лампы ИН-1 номера выводов соответствуют электродам-цифрам, 10 вывод 0, 11 – анод. На разобраной плате индикации (только она ИН-14 ИН-19 ) на каждую лампу на анод подается напряжение через 56 килоом, там была динамическая индикация, одна ИД1 на 4 цифры и другая на знаки. При таком способе одновременно горит только одна лампа, у всех четырех одинаковые цифры соединены вместе. Это не сильно проще, экономятся только регистры и немножко проводов, только вот хуже яркость и могут лампочки моргать. *при динамической индикации чуть меньше ток потребления и меньше возможность отравления неработающих электродов, против отравления делается включение всех цифр раз в минуту перебором за 3-5 секунд, и лучше выключать на ночь, включение по датчику движения например.







Ни хрена се.. Гроза в Москве 17 сентября , это что же творится… Наверно катушка Теслы тут не при чем, жарко как летом 23.



















Декатрон от сетевого напряжения не загорается (если посветить фонариком который на другой странице – зажигается). Для этой штуки надо 450 вольт, а для ламп 300 вольт, используется 155ИД1 и ИН-1 большие с круглым корпусом под панельку. ИН-1 могут зажигаться от 230.. 250 но лучше подобрать 280 .. 300 в темноте напряжение ионизации газа выше. Без панелек обойдусь. По инструкции к лампам ИН-12 с жесткими штырьками их можно паять не дольше 3 секунд на расстоянии не ближе 4 мм от стекла. Лампы достались чуть ли не с трещинами, проверил все поднося к катушке Теслы, трещины покрываю цапон лаком. Разбитые совсем не восстанавливаю, хотя есть умелец уже делает их сам, вакуумный насос для ремонта холодильников стекло газ аргон неон водород, вакуумный насос более мощный, стеклодувные горелки, это на миллиона 3 денег, хотя окупится – ну это целая фабрика, китайским компаньонам надо сказать. Металлы там недешевые, никель молибден электроды таблетка из редкоземельных церий и др . ( Торий вольфрам и немножко радиоизотопа на ИН-3, уберу лампы за лист оргстекла в 1 см толщиной, это надо и есть дозиметр чтобы проверить. Вот не игрушка а довольно серьезная опасность, раньше не задумываясь делали, да и семья из Припяти). Внимание надо к элементам разобранных ламп и других устройств до 80-х годов, часы со стрелками покрытыми радием например это 1400 микрорентген. Молниеотводы лампы многие тиратрон игнитрон могут содержать добавку, она применялась для работы при низком напряжении 30- 70 вольт а не 300 – 400 и облегчала зажигание ламп.
Источник высоковольтный на 1 микросхеме 34063 и у трансформатора отвод от второй обмотки. Да, по такой схеме сильные затухающие колебания и по первичной и по вторичной обмотке, но потеря мощности на них небольшая.


RC dempfer snabber надо добавить. Детали вч трансформатор конденсаторы и 2 диодика из балласта к люминесцентной лампе, до 600 вольт все таки поставлю провереный КД226 – он если что выдерживает импульс в 50 и больше ампер, даже можно по схеме с индуктивностью собрать, из 12 в 500 вольт и отвод все таки, а можно и второй модуль на 300 вольт. Ток декатрона 0.6 миллиампер 450в, ток всех ламп 5 миллиампер от 300 вольт, это максимум, сделаю поменьше если достаточная яркость будет. Есть другая схема с MPSA42 транзистором, подключенным эмиттером к 1 выходу микросхемы 34063 и с удвоителем напряжения, тоже работающий вариант. Наш аналог КТ940А только чуть больше размером и надо на маленький радиатор ставить, схема с полевиком чуть более экономичная, на китайской я даже smd индуктивность не менял, греется но не больше 30 градусов. * В блоке питания все рассчитывается, катушка тоже, тут инженерной прикидки маловато будет. Транзисторы КТ940А будут управлять декатроном там надо 4 штуки на 1 декатрон или 3, MPSA42 тоже подойдет, 300 вольт хватит. На декатрон питание через пол-мегома резистор а по описанию можно и побольше, до 1.5 МОм, ток должен быть до 0.6 ма при 420 вольт для А101. Если будут загораться все штырьки сразу то надо подбирать по яркости, лучше больше чтобы быстро не перегорел, при большом токе через 1 штырек и медленном перемещении огонька соседние штырьки отравливаются. Для их очистки надо раз в 30 секунд – 5 минут сбрасывать декатроны и прогонять их 30 секунд с большой скоростью лучше 50 раз в секунду и по одному электроду, переключая разряд с одного на другой, не зажигая несколько. Примерно такой же способ очистки у цифровых ламп, тоже надо все электроды позажигать которые работают. ** выбрал Декатрон Шилд – ниже – 2 транзистора подают сигналы на g0 g1 и снимается сигнал с k0.


Вот этот эффект на декатроне показывает секунды. Он делается 2-мя импульсами, разряд возникает на одной точке и переносится дальше, предыдущая может гаситься а может и нет. (более красиво когда не гасится только надо будет яркость и ток подбирать).* в один момент времени горит 1 штырек – смотрим код Слинки пружинки. Несколько не надо пытаться зажигать – лампа не рассчитана на это. на схеме шилда где декатрон работает от ардуино – вся логика работы понятна, точно как по старому описанию – 2 сигнала управления и считывается индекс – как только разряд на контакте к0. Можно назад запустить. Есть сброс после которого огонек вернется на начало у первого вывода. Там если не ошибаюсь 31 штырек – 30, последний это выход, деление частоты на 10. Описание есть здесь. (прибор интересный – при обычном включении разряд переносится на 1 полукатод потом на 2-й – за разряд отвечают 3 штырька, заполненые водородом АГ3 и А107 синего свечения им надо 450 вольт и они работают до 20 килогерц, А101 оранжево красным светится и только 1500 -2000 герц, и ярче зато // A108 до 1 мегагерца не проверено водород гелий синий разряд, А-101 только до 1000 герц если 420 вольт 570 килоом 100 и 230 вольт на подкатодах – они на снимке часов разряд оранжевый неон гелий).




А101 МЭЛЗ – описание взято с сайта www.155la3.ru / Лампа ВП Номер 3062 5-69 со значком московского электролампового завода – заводы не выпускают эти лампы с 90-х ( http://melz-elt.ru/ другой в Дятьково Брянской обл. там ООО на остатках закрытого предприятия – проезжал от Брянска в Людиново очень торопились дорога разбитая была в 2013 вусмерть, 80 километров Брянский лес , на колесах пораскручивались ниппели так трясло,на 100 км в час можно еще проехать а на 60 как стиральная доска).


есть видео клип – проверка лампочек
Вот схема крутилки на декатроне – там в тексте развернутом написано какие выводы у декатрона соединять. Радиолюбитель возмет 2 проводка и тестер Ц-20 если надо замерит им 600 вольт – надо 400 а то и от 300 многие работают, 310 вольт делается из розетки через диод и емкость 1мкф 250в – от лампы дневного света или от телефона, блоков питания. А 600 – 620 вольт через 2 диода и 2 таких конденсатора по схеме удвоителя она тут есть в 4 местах. И все выводы проверит у неонки ГРИ или декатрона .Только подавать напряжение надо через большой резистор на 500 килоом -он ограничит ток через лампу и конечно за оголенные провода не хвататься. Таблица декатронов сбоку у схемы, посмотрев на эту схему а она фактически автогенератор на неонке, я задумал сделать управление на 4 транзисторах высоковольтных и от ардуино или микроконтроллера. * Уже все это сделано arduino decatron shield или поиском ..нецелевое использование декатронов..
Не зря на картинках выскакивает изображение ядерного взрыва, и там и у нас счетчик импульсов был в то время – 50-60е годы на декатронах. Так что атомные и водородные бомбы испытывали как раз с применением этих индикаторов. От счетчика Гейгера сразу видно сколько разрядов. А коммутаторный еще и включить что то мог – по 8 -9 -10 импульсу например. (табличку опасно радиация).
наш транзистор КТ940А или который на схеме – они по 18 рублей.
еще – doppel dekatron schaltplan .. double decatron schematic есть крутилка на двух декатронах схема.


Внимательнее изучаем инструкцию эта вон те похоже накосячили какой то проводок замкнул..




Применяется А-101 . Еще одна идея – пересмотрел какие схемы похожие есть и конструкции, у этого декатрона несколько выходов. Пусть он зажигает еще одну цифровую лампу, есть 2 примера в одном через транзисторы включаются светодиоды вокруг декатрона а в другом ИН-12 . Вот ее как раз и возьму, расположение тогда верхний ряд 6 штук ИН-1 а снизу 2 декатрона. И повтор на цифрах ИН-12. Не совсем так, на декатроне можно не только по одному катоду зажигать а и все по порядку, на лампе тогда загорятся несколько цифр.. Пересмотрел и проект блока питания, расточительство по питанию ни к чему, будет от батареи литиевой. Разработаный блок здесь – от 3 вольт для фонаря, страница Фонарик на светодиоде, секрет его в установке такого режима для полевого транзистора при котором самые маленькие потери, управление и вч трансформатор. По предварительным данным можно снизить питающее напряжение до 390 – 400 вольт и 200 вольт на ИН-1 они еще статическую индикацию используют, и нужна ли такая экономия – можно взять парочку кондеров от блока питания они на 400 вольт и менее высоковольтные транзисторы. Нет неверный подход раньше на мелочах не экономили, слюдяные кондеры на 500 – 600 вольт на ламповых устройствах, поставлю парочку. (есть сейчас пленочные типа К78-2 например). Бумажные КБГ 2 киловольта не не , старинные уже, осторожнее с ними только особенно если ток переменный и напряжение на пределе, у них безопасность сравнима с канистрой бензина стоящей у костра к примеру. Он наполненый маслом – есть и без масла и как раз для ламповой техники, сильного возгорания не было а хлопок намного громче чем у заброшеной метров на 20 лимонки вот прямо в ушах звенит до сих пор и настолько же вероятность столкновения с кусочками металла, часть с выводами выдирал из досок потолка дюймовки да ее насквозь почти прошило. хорошо отошел в сторонку случайно. Одна из причин почему корпуса техники делались из металла прочного и тяжелого. Пусковой кондер можно купить или взять от какого электромотора, он дешевле и боле спокойно себя ведет.
код для проверки – Слинки 4 страницы вниз. Index=P7.
Код программы от индикатора уровня громкости (видео есть на сайте у американца, на ютюб ссылка).
/*
Dekatron Analog Gauge 2 Example - with Timer IRQ
modified April 7, 2017
by Michael Moorrees ** заработало сразу - если надо можно внести задержку в цикл 20мс
*/
include
int Scnt = 67; // step count
int state = 0; // State - Machine State
int dk_ct = 0; // Dekatron Guide count - 0,1, or 2
int LED = 13; // Test LED
int Guide1 = 5; // Guide 1 - G1 pin of 2-guide Dekatron
int Guide2 = 6; // Guide 2 - G2 pin of 2-guide Dekatron
int Index = 7; // Index - NDX input pin. High when glow at K0
int Ndx = 0; // K0 index indicator variable
int Tick = false; // 500uS tick
int Icnt = 250; // Idle counter
int ct_10 = 20; // 10mS counter
int in_val = 0; // ADC value scaled
//int sensorPin = A0; // Analog input 0
int sensorPin = 0; // Analog input 0
// setup() runs once, at reset, to initialize system
// initialize hardware and preset variables
void setup() {
Timer1.initialize(500);
Timer1.attachInterrupt( timerISR );
pinMode(Guide1, OUTPUT);
pinMode(Guide2, OUTPUT);
pinMode(Index, INPUT);
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
Scnt = 67;
state = 0;
Ndx = 0;
D_adv();
}
void d_step(int dk_bt) // Dekatron Step
{
if (digitalRead(Index)) Ndx = true; // Sample for glow at K0
switch (dk_bt) {
case 0: // glow at a main cathode
digitalWrite(Guide1, LOW);
digitalWrite(Guide2, LOW);
break;
case 1: // glow to a Guide 1 cathode
digitalWrite(Guide1, HIGH);
digitalWrite(Guide2, LOW);
break;
case 2: // glow to a Guide 2 cathode
digitalWrite(Guide1, LOW);
digitalWrite(Guide2, HIGH);
}
}
void D_adv() // Dekatron Advance - Clockwise
{
dk_ct ;
if (dk_ct == 3) dk_ct = 0;
d_step(dk_ct);
}
void D_rev() // Dekatron Reverse - Counter-Clockwise
{
dk_ct--;
if (dk_ct == -1) dk_ct = 2;
d_step(dk_ct);
}
//
// Idle - States (0 - 3)
//
void dk_action0() { // Dekatron Action Routine 0 - Slow CW
if (Ndx) { // When glow hits Ndx [K0] cathode,
D_rev(); // step CCW
Ndx = false; // go to state 1
state = 1; //
Scnt = 67; // preset 33mS
}
else { // Continue CW if not at Ndx
Scnt--; //
if (Scnt==0) { //
D_adv(); // CW one step every
Scnt = 67; // 33mS
}
}
}
void dk_action1() { // Dekatron Action Routine 1 - Coast CCW
Ndx = false; //
Scnt--; //
if (Scnt==0) { // After 33mS
D_rev(); // step once CCW
Ndx = false; // go to state 2
state = 2; //
Scnt = 66; //
}
}
void dk_action2() { // Dekatron Action Routine 2 - Slow CCW
if (Ndx) { // When glow hits Ndx [K0] cathode,
D_adv(); // step CW
Ndx = false; // go to state 3
state = 3; //
Scnt = 67; // preset 33mS
}
else { // Continue CCW if not at Ndx
Scnt--; //
if (Scnt==0) { //
D_rev(); // CCW one step every
Scnt = 67; // 33mS
}
}
}
void dk_action3() { // Dekatron Action Routine 3 - Coast CW
Ndx = false; //
Scnt--; //
if (Scnt==0) { // After 33mS
D_adv(); // step once CCW
Ndx = false; // go to state 0
state = 0; //
Scnt = 66; //
}
}
void dk_action4() { // Dekatron Action Routine 4 - Return 2
if (Ndx) { // Return to Ndx, CCW
Ndx = false; // finally at Ndx, go to state 5
state = 5; // set Scnt per ADC for excursion
Scnt = in_val;
if (Scnt==0) Scnt = 1;
}
else {
D_rev();
}
}
void dk_action5() { // Dekatron Action Routine 5 - Gauge to Scnt CW
if (Scnt==0) { //
Ndx = false; // when Scnt dots out, go to state 4
state = 4; //
}
else { // go Scnt dots CW
Scnt--; //
D_adv(); //
}
}
void I_tmr() {
if (in_val < 2) { // digitalWrite(LED, LOW); if (Icnt==0) { if (state > 3) {
state = 0;
Scnt = 1;
}
}
else Icnt--;
}
else {
Icnt = 250;
// digitalWrite(LED, HIGH);
if (state < 4) {
state = 4;
Scnt = 1;
}
}
}
// Main Loop - State Machine
//
// States: 0 -> 1 -> 2 -> 3 -> 0 Idle
// 4 -> 5 -> 4 Gauge (when analog above threshold)
//
void loop() {
if (Tick) {
Tick = false;
switch (state) { // Do action per current state
case 0:
dk_action0(); // Idle: Slow_CCW
digitalWrite(LED, LOW);
break;
case 1:
dk_action1(); // Coast_CCW
digitalWrite(LED, HIGH);
break;
case 2:
dk_action2(); // Slow_CW
digitalWrite(LED, LOW);
break;
case 3:
dk_action3(); // Coast_CW
digitalWrite(LED, HIGH);
break;
case 4:
dk_action4(); // Gauge: Return 2
break;
case 5:
dk_action5(); // Gauge_CW
}
ct_10--;
if (ct_10==0) { // Every 10mS: Read ADC
ct_10 = 20;
in_val = analogRead(sensorPin)/35; // 0-5V
// in_val = analogRead(sensorPin)/56; // Microphone Option
I_tmr(); // Idle Timer
}
}
}
void timerISR() {
Tick = true;
}
Все таки 390 и 180 вольт – с обмотки одной, еще и 50-60 вольт а с другой можно 5 вольт, все таки 6 штук К155ИД1 это почти 2 ватта по 5 вольтам, линейный сильно нагреется. от 220 вольт выпрямленного то есть 307 декатрон зажигается с трудом надо больше – по паспорту 420 вольт, там добавка для снижения ионизации, водород наверно. Если разряд есть то при снижении напряжения до 180 он будет гореть.

это 2 клипа видео с dailymotion – чего то политика не в ту сторону работает, весь сайт отключен, смотрел через французи. Коммутаторный декатрон зажигает светодиоды – разряд перебрасывается на следущие штырьки..
В частотомере используются первые 2 декатрона с синим разрядом – он не такой яркий но очень скоростной до миллиона в секунду – на водороде повидимому и гелии. А потом оранжевые – гелий неон. Те что у меня А101 работают до 1500 герц, не очень шустрые а вот разряд красивый краснее чам неонка. Разница есть и как между лампами с газовым разрядом – плазма рыжая это неон а более красная гелий в смеси и ртуть – зелено белый добавляется в высокой частоте если проверять катушкой Теслы.. Ртуть увеличивает время работы ламп как считается с 500 до 5000 часов , на самом деле могут работать несколько лет если не перегружать большим током – резистор в цепи анода у декатрона 750 килоом а у ламп – подобрать – еслми 165 вольт то 30 килоом, для ИН 14, если 305 вольт то 75 килоом или больше даже это для ИН 1.
еще где то видео где декатрон зажигает светодиоды и трубку Никси, только красиво если один огонек бегает. А самый красивый эффект даже не маятник а как в глазке от лампового усилителя VU-meter magic eye. Я такую штуку застал еще – в катушечном магнитофоне это был уровень записи, сейчас есть лампа советская и китайская они разные. Это зеленого свечения глазок и там чем больше звук тем больше засветка ! будет, часы могут быть совмещены с приемником или блютуз колонкой. Волюметер лучше по русски измеритель громкости, неправильно язык искажать – если русских слов нет они появятся. На декатроне еще красивее , чем больше сигнал тем больше штырьков катодов загораются – смотрим на плазму а это четвертое состояние вещества. (программа к ардуино чуть выше) .Еще один эффект – секунды – перемещается огонек по кругу и зажигает все штырьки за ним а потом так же гасит начиная с первого.

Кондер если на 16 или 25 киловольт и большую мощность реактивную (5К вар) огромный при емкости небольшой относительно и его цена в 200 000 р не предел. К чему это я – на снимке под декатроном его разумная замена – иногда подходит в виде полусотни таких же который под декатроном – советский К78-2 – можно индукционную печь там или катушку Теслы микроволновку на 5 киловатт.. радио локатор. Он до 120 градусов может работать – из полипропилена.
Работа повышающего преобразователя. По русски это есть в статье Фонарик на светодиоде там такой же преобразователь dc-dc второй режим усложняет схему наверно не надо экономия на катушке увеличит расходы на остальные компоненты и добавит еще полевик.

распишу связку ардуины с регистрами pa0 pa1 pa2. Как на 7-сегментниках, только Никси, на 3 байта отправленых в регистры получается 6 цифр часы минуты секунды, (давление температура улицы и дома с задержкой полсекунды. и еще на декатроне – уровень сигнала или маятник или секунды. Смотря какие датчики у ардуинки).
чуть более точно – используется d12 d11 d8 digital как в библиотеке shiftout.
кусочек схемы в точности есть выше только под 2 лампы а здесь 6 / hc595 К155ИД1 2 штуки – 2 лампы/ поскольку применяется ИД1 и лампы ИН1 будет подбор напряжения. ** 195 185 вольт по остаточному свечению, резисторы анодные 56к 39к 22к 18к 10к – последние 2 либо при маленьком напряжении либо при Розжиге ламп – снятии остаточного отравления катодов. * Источник dc-dc при 12-вольтовом питании легко выдает 30 ватт . В конструкцию ставится 2 маленьких ардуинки – кому не нравится дорого не кошерно или еще что есть все исходники – можно пересобрать на stm8 stm32 скорее. Да хоть на 8051 или pic16.
his by controlling the MR and OE pins from your Arduino board too, but this way will work and leave you with more open pins.

2. Connect to Arduino
- DS (pin 14) to Ardunio DigitalPin 11 (blue wire)
- SH_CP (pin 11) to to Ardunio DigitalPin 12 (yellow wire)
- ST_CP (pin 12) to Ardunio DigitalPin 8 (green wire)
то есть защелка к d8 а не как здесь d10 – у AlexGyver вроде как d3 d4 d5 вариантов несколько.
13 -oe выход включен – на землю конечно 10 -mr то есть сброс на плюс.
есть выше схема где 12 строб st_cp соединен с 13 я считаю не совсем корректно, переключать выходы каждый раз не сильно нужно. По физике на переключение уходит энергия. там есть z-state то есть отключение выхода, устанавливается за какие то нано секунды неопределенное состояние, не уверен но на отключенном выходе может напряжение разогнаться из -за наводки еще – если провода длинные.


настройка блока питания – выходы 560в 200в 4 или 6 вольт – все с одной катушки. Регулируется mc34063 по 560 вольтам, попробую может еще более экономично снизить до 4.5 вольт (или даже до 3.8 с одним витком) посмотрю как будут работать ид1 – ардуинка запускается от 3 с небольшим вольт. ин1 чуть больше ток требуют – 6 ламп пока 5 ватт – с декатроном.
224v 603v 6v 3.6 watt – подобрал 2 витка для 5 вольт. Может сделаю 1 виток и потолще проводом, тогда диод Шоттки . Сейчас КД213, на нем падение меньше 0.7 вольта. а так будет 0.4. Еще попробую по 5 вольтам регулировку. Попробую снизить мощность, микросхемы дешифраторов * с перенакалом не надо. 180 витков примерно в изоляции пэтф фторпласт, на 600 вольт нормально. Сейчас включу по 2 цифры на ИН 1 и посмотрю мощность – декатрон работает, на нем меньше полватта.
После очередного ремонта китайско платы под ин-14 поставил dc dc сзарядкой телефона 2а . ток потребления снизился до 180 ма от 12 вольт, это без светодиодов. На транзитсор усилитель на КТ361 КТ315 – он уменьшает нагрев и потребление тока в 2 раза – меньше сопротивление открытого полевика и его время переключения. Можно было намотать катушку трансформатор но оставил дроссель и отдельный модуль 5 вольт из 12. (вместо 78l05 – а то 2 раза сгорала и с ней регистры 74НС595)
Проверку соединений удобно сделать обычным тестером. – можно и осциллографом посмотреть как дергается сигнал на ножках. Тестер на режиме прозвона диодов и плюс на землю а минус к электродам ламп . Анод не звонится а на остальных сопротивление защитного диода в ИД1 в обратном направлении то есть к лапке и к электроду лампы прикладывается отрицательное в 3 вольта с тестера. Показывает 100 .. 600 ом это правильно ток идет через защитный диод – подложку в микросхеме и значит соединение проводом есть. ( если соединение косичкой или плоским кабелем с разьемами – точно так же прозвонка). На входах к155ИД1 смотрим осциллой – вот уж точно дергаются ножки раз в секунду или 10 раз или 2 раза в минуту – смотря какой код цифры. Если сигнал четкий ноль и единица с выходов регистров то все соединения правильные . Начинающим. Сначала прозванивается питание . и земля. Что питание никуда не заамыкает а соединяется куда нужно. При первом включении каску лист оргстекла 10 см защиту и наушники стрелка. и рядом огнетушитель. А сам блок питания полярность проверили? А модуль или плату MC34064 – порядок проверки – земля на 4 ножке – на силовом транзисторе – на конденсаторе задающем частоту (запустится на 400 килогерц без него – не очень хорошо полевик перегреется и диоды тоже). Питание на резисторе 0.2 и на 6 лапе и на силовой катушке – Больше никуда кроме плюса кондеров! С резистора 0.2 на 7 лапу на 8 через 180 ом или 100 как по схеме и на 1. При первой проверке можно отсоединить выход (2 лапу) от базы 2 транзисторов pnp npn и подключить через 1 килоом на землю – и смотреть сигнал – он должен быть вот такой (и посмотреть сигнал пилы на 3 лапке у меня получается – вход у советского осциллографа мегаом и 42пф – это не нарушает работу ! Но может нарушить работу материнки или телефона или цифровой техники где частота выше 10 мегагерц, сигнал уйдет даже через такую маленькую емкость и просядет немножко или сильно – тактовый или стробы и вч цепи собьются будет помеха но не должны поломаться).
Поехали.
Чтобы все запустилось после проверки соединений – надо загрузить програмки в Ардуино. Но сначала проверяем все соединения – особенно высокое напряжение и плюс источника 5 вольт и землю тоже. Никуда не должны замыкать красная желтая и черная линия!! Только соединяться куда надо.. Тестер с припаяными иголочками к щупам поможет.
Им же меряем 600 198 120 56 12 входное и 5 вольт. Путем шаманства с полутора витками и подбором при всех включнееых элементах на линии +5 вольт установилось 4.89 – это то что надо. Ясен пень что трогать плюсовой на кондере к78-2 киловольт на 1 микрофараду не советуется, ярчайшая вспышка и отбросит на метра два, можно нечистую силу не успеть позвать. ** 800 на 600 разряжал нижней губой – отбросило и ходил с красивым шрамом месяца два – повезло вообще то очень. (0.66 мкф на практике установлено – хватит.)
Декатрон эффект пружинки Слинки.
Код без исправлений у автора Ардуино Шилд. только поменял линии D5 D6 и D7 Вход с катода К0 . Обязательно установлен стабилитрон zener diode 4.7 v. Сгоревших ардуинок не надо.
код для эффекта пружинки (кроме красивого эффекта эта программа очищает декатрон от отравления).
threeneurons.wordpress.com для ардуинки у декатрона G1 =5 через 1-й транзистор кт940а G2= 6 index = 7 сигнал с K0 через транзистор кт503е (он на 90 + вольт или mp sa92) смотрим на видео, еще видео будет ночью. На этом даже скорости не хватает, надо 60 кадров в секунду или больше. Пример программы с хорошими комментариями и заработавшей сразу.
/* Dekatron Slinky Example - with Timer IRQ modified April 7, 2017 by Michael Moorrees Santosha - add delay 400 milli seconds - work in progress - effects or show 1- second rotation - or 2 seconds glow (30 pins) read input pin */ #include int swing = 2; // swing range - 2 to 30 int Scnt = 0; // step count int state = 0; // State - Machine State int dk_ct = 0; // Dekatron Guide count - 0,1, or 2 int LED = 13; // Test LED int Guide1 = 5; // Guide 1 - G1 pin of 2-guide Dekatron int Guide2 = 6; // Guide 2 - G2 pin of 2-guide Dekatron int Index = 7; // Index - NDX input pin. High when glow at K0 int Ndx = 0; // K0 index indicator variable int Tick = false; // 1mS tick void d_step(int dk_bt) // Dekatron Step { if (digitalRead(Index)) Ndx = true; // Sample for glow at K0 switch (dk_bt) { case 0: // glow at a main cathode digitalWrite(Guide1, LOW); digitalWrite(Guide2, LOW); break; case 1: // glow to a Guide 1 cathode digitalWrite(Guide1, HIGH); digitalWrite(Guide2, LOW); break; case 2: // glow to a Guide 2 cathode digitalWrite(Guide1, LOW); digitalWrite(Guide2, HIGH); } } void D_adv() // Dekatron Advance - Clockwise { dk_ct++; if (dk_ct == 3) dk_ct = 0; d_step(dk_ct); } void D_rev() // Dekatron Reverse - Counter-Clockwise { dk_ct--; if (dk_ct == -1) dk_ct = 2; d_step(dk_ct); } void dk_action0() { // Dekatron Action Routine 0 - Grow from Bottom, Forward (cw) if (Ndx) { // When swing hits Ndx [K0] cathode, then max swing is achieved Ndx = false; // Set vars for next state, and jump to state 2 state = 2; swing = 30; Scnt = (swing / 2) - 1; digitalWrite(LED, HIGH); } else { // If not at K0 yet, but stepped "swing" number of steps if (Scnt == 0) { // increment swing length, preset count swing++; // and jump to state 1, for reverse stepping Scnt = swing; state = 1; } else { // otherwise, continue stepping forward, Scnt--; // while decrementing step counter. D_adv(); } } } void dk_action1() { // Dekatron Action Routine 1 - Grow from, either bottom, or top, Reverse (ccw) if (Scnt == 0) { // at full steps (count = 0), increase swing, preset count state--; // and jump to forward growth state (0 or 4) swing++; // This routine is called while in either state 1 (bottom) or state 5 (top) Scnt = swing; } else { // If not yet at full step Scnt--; // contiue stepping in reverse D_rev(); // while drecrementing counter } } void dk_action2() { // Dekatron Action Routine 2 - Shrink from, either bottom, or top, Forward (cw) if (swing < 2) { // until swing is at minimum (2) state = (state + 2) & 7; // then jump to state 4 (if at 2 - top) or 0 (if at 6 - bottom) // if (state == 2) state = 4; // if (state == 6) state = 0; swing = 2; Scnt = swing; Ndx = false; } else { // at full forward step (count = 0), if (Scnt == 0) { // decrease swing length, preset count swing--; // and go to reverse shrink state: Scnt = swing; // state 3 (if at state 2 - top) or state++; // state 7 (if at state 6 - bottom) } else { Scnt--; // Otherwise, contine stepping forward D_adv(); // while decrementing counter } } } void dk_action3() { // Dekatron Action Routine 3 - Shrink from, either bottom, or top, Reverse (ccw) if (Scnt == 0) { // at full steps (count = 0), state--; // decrease swing length, and jump to swing--; // state 2 (if at state 3 - top) or Scnt = swing; // state 6 (if at state 7 - bottom) } else { // Otherwise, continue stepping in reverse Scnt--; // while decrementing counter D_rev(); } } void dk_action4() { // Dekatron Action Routine 4 - Grow from Top, Forward (cw) if (swing >= 30) { // When swing length reaches 30 (maximum), state = 6; // jump to state 6, and preset swing and count swing = 30; Scnt = (swing / 2) - 1; } else { // If not yet at full swing, but hit maximum steps, if (Scnt == 0) { // (count = 0), then increase swing length, swing++; // preset count and go to state 5 (reverse) Scnt = swing; state = 5; } else { // Otherwisw, continue stepping forward Scnt--; // while decrementing counter. D_adv(); } } } // setup() runs once, at reset, to initialize system // initialize hardware and preset variables void setup() { Timer1.initialize(1000); Timer1.attachInterrupt( timerISR ); pinMode(Guide1, OUTPUT); pinMode(Guide2, OUTPUT); pinMode(Index, INPUT); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); swing = 2; Scnt = 0; state = 0; Ndx = 0; D_adv(); } // Main Loop - Slinky Pattern State Machine // // States: 0 <--> 1 until max swing [Growing, at bottom] // 2 <--> 3 until min swing [Shrinking, at top] // 4 <--> 5 until max swing [Growing, at top] // 6 <--> 7 until min swing [Shrinking, at bottom] // at min go back to state 0 // void loop() { if (Tick) { Tick = false; switch (state) { // Do action per current state case 0: dk_action0(); // Grow from Bottom, Forward break; case 1: dk_action1(); // Grow, Reverse break; case 2: dk_action2(); // Shrink, Forward digitalWrite(LED, LOW); break; case 3: dk_action3(); // Shrink, Reverse break; case 4: dk_action4(); // Grow from Top, Forward break; case 5: dk_action1(); // Grow, Reverse break; case 6: dk_action2(); // Shrink, Forward break; case 7: dk_action3(); // Shrink, Reverse } // delay(1); // Pause 1mS } } void timerISR() { Tick = true; }
Для желающих разобраться в работе.. студенты глядим сюда тоже – все великие прогромисты с этого начинали. Задержка в код и понятно что и как работает. В один момент времени загорается только один огонек на декатроне, потом он прыгает на соседний штырек .. ждем 400мс чтобы увидеть куда .. потом рисует правую часть фигуры – так же с центра вниз и вверх, а потом к центру.. получается пружинка. ves kod dlya prosmotra kak rabotaet// ‘это для желающих разобраться
/* 0 1 2 3 Dekatron Slinky Example - with Timer IRQ modified April 7, 2017 by Michael Moorrees */ #include int swing = 2; // swing range - 2 to 30 int Scnt = 0; // step count int state = 0; // State - Machine State int dk_ct = 0; // Dekatron Guide count - 0,1, or 2 int LED = 13; // Test LED int Guide1 = 5; // Guide 1 - G1 pin of 2-guide Dekatron int Guide2 = 6; // Guide 2 - G2 pin of 2-guide Dekatron int Index = 7; // Index - NDX input pin. High when glow at K0 int Ndx = 0; // K0 index indicator variable int Tick = false; // 1mS tick void d_step(int dk_bt) // Dekatron Step { if (digitalRead(Index)) Ndx = true; // Sample for glow at K0 switch (dk_bt) { case 0: // glow at a main cathode digitalWrite(Guide1, LOW); digitalWrite(Guide2, LOW); delay(400); break; case 1: // glow to a Guide 1 cathode digitalWrite(Guide1, HIGH); digitalWrite(Guide2, LOW); delay(400); break; case 2: // glow to a Guide 2 cathode digitalWrite(Guide1, LOW); digitalWrite(Guide2, HIGH); delay(400); } } void D_adv() // Dekatron Advance - Clockwise { dk_ct++; if (dk_ct == 3) dk_ct = 0; d_step(dk_ct); } void D_rev() // Dekatron Reverse - Counter-Clockwise { dk_ct--; if (dk_ct == -1) dk_ct = 2; d_step(dk_ct); } void dk_action0() { // Dekatron Action Routine 0 - Grow from Bottom, Forward (cw) if (Ndx) { // When swing hits Ndx [K0] cathode, then max swing is achieved Ndx = false; // Set vars for next state, and jump to state 2 state = 2; swing = 30; Scnt = (swing / 2) - 1; digitalWrite(LED, HIGH); } else { // If not at K0 yet, but stepped "swing" number of steps if (Scnt == 0) { // increment swing length, preset count swing++; // and jump to state 1, for reverse stepping Scnt = swing; state = 1; } else { // otherwise, continue stepping forward, Scnt--; // while decrementing step counter. D_adv(); } } } void dk_action1() { // Dekatron Action Routine 1 - Grow from, either bottom, or top, Reverse (ccw) if (Scnt == 0) { // at full steps (count = 0), increase swing, preset count state--; // and jump to forward growth state (0 or 4) swing++; // This routine is called while in either state 1 (bottom) or state 5 (top) Scnt = swing; } else { // If not yet at full step Scnt--; // contiue stepping in reverse D_rev(); // while drecrementing counter } } void dk_action2() { // Dekatron Action Routine 2 - Shrink from, either bottom, or top, Forward (cw) if (swing < 2) { // until swing is at minimum (2) state = (state + 2) & 7; // then jump to state 4 (if at 2 - top) or 0 (if at 6 - bottom) // if (state == 2) state = 4; // if (state == 6) state = 0; swing = 2; Scnt = swing; Ndx = false; } else { // at full forward step (count = 0), if (Scnt == 0) { // decrease swing length, preset count swing--; // and go to reverse shrink state: Scnt = swing; // state 3 (if at state 2 - top) or state++; // state 7 (if at state 6 - bottom) } else { Scnt--; // Otherwise, contine stepping forward D_adv(); // while decrementing counter } } } void dk_action3() { // Dekatron Action Routine 3 - Shrink from, either bottom, or top, Reverse (ccw) if (Scnt == 0) { // at full steps (count = 0), state--; // decrease swing length, and jump to swing--; // state 2 (if at state 3 - top) or Scnt = swing; // state 6 (if at state 7 - bottom) } else { // Otherwise, continue stepping in reverse Scnt--; // while decrementing counter D_rev(); } } void dk_action4() { // Dekatron Action Routine 4 - Grow from Top, Forward (cw) if (swing >= 30) { // When swing length reaches 30 (maximum), state = 6; // jump to state 6, and preset swing and count swing = 30; Scnt = (swing / 2) - 1; } else { // If not yet at full swing, but hit maximum steps, if (Scnt == 0) { // (count = 0), then increase swing length, swing++; // preset count and go to state 5 (reverse) Scnt = swing; state = 5; } else { // Otherwisw, continue stepping forward Scnt--; // while decrementing counter. D_adv(); } } } // setup() runs once, at reset, to initialize system // initialize hardware and preset variables void setup() { Timer1.initialize(1000); Timer1.attachInterrupt( timerISR ); pinMode(Guide1, OUTPUT); pinMode(Guide2, OUTPUT); pinMode(Index, INPUT); pinMode(LED, OUTPUT); digitalWrite(LED, LOW); swing = 2; Scnt = 0; state = 0; Ndx = 0; D_adv(); } // Main Loop - Slinky Pattern State Machine // // States: 0 <--> 1 until max swing [Growing, at bottom] // 2 <--> 3 until min swing [Shrinking, at top] // 4 <--> 5 until max swing [Growing, at top] // 6 <--> 7 until min swing [Shrinking, at bottom] // at min go back to state 0 // void loop() { if (Tick) { Tick = false; switch (state) { // Do action per current state case 0: dk_action0(); // Grow from Bottom, Forward break; case 1: dk_action1(); // Grow, Reverse break; case 2: dk_action2(); // Shrink, Forward digitalWrite(LED, LOW); break; case 3: dk_action3(); // Shrink, Reverse break; case 4: dk_action4(); // Grow from Top, Forward break; case 5: dk_action1(); // Grow, Reverse break; case 6: dk_action2(); // Shrink, Forward break; case 7: dk_action3(); // Shrink, Reverse } // delay(1); delay(200); // Pause 1mS } } void timerISR() { Tick = true; }
тестовая программа (рабочая!) если что не собирается смотрим каких библиотек не хватает и их надо скачать и распаковать в arduino – library каталог. Исправлять подключение к Ардуино если надо – d11 выход на регистр первый на 14 , потом с него поцепочке на второй с 9 лапы на 14, со второго на третий. К первому часы, второй -минуты, третий – секунды. d12 на 11 лапы, d8 на 12-е. программа зпжигает нолики на всех лампах и перебирает все цифры раз в секунду от отравления катодов.
а nixie tube driving by Arduini nano - 6 tubes ИН1, 3 -74hc595 6 - К155ИД1 по русски тест соединений // // з байта в гекс - заталкиваются последовательно в регистры // если включена отладка debug=true то надо открыть монитор com порта в программе ардуино - порт это конечно кабель юсб к компьютеру а com виртуальный. Если опять не работает или сразу зависает - отсоединить проводки от модуля часов он может зависать. В первых 4-х строчках настроить правильно лапки для подключения регистров (надо 3 исправных - если поломка - проверить проще всего светодиодной линейкой) #include #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 12 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 #define NUM_REGISTERS 3 //how many registers are in the chain //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable void setup(){ pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); Serial.begin(9600); } void loop(){ byte second, minute, hour; // shifter.setAll(HIGH); nixietrainer(); shifter.clear(); shifter.write(); //send changes to the chain and display them delay(200); second = 86; minute = 79; hour = 78; displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// use 74141 shifter.write(); delay(5000); //set all pins on the shift register chain to LOW // shifter.write(); //send changes to the chain and display them shifter.clear(); //delay(2000); shifter.write(); // shifter.setPin(0, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(1, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(2, LOW); shifter.setPin(3, LOW); // shifter.setPin(4, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(7, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, LOW); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(14, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(20, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(21, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(22, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.write(); shifter.clear(); delay(100); //} //void looptest(){ // byte second, minute, hour; second = 81; minute = 42; hour = 69; displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(3000); shifter.clear(); shifter.write(); delay(100); nixietrainer(); shifter.setAll(HIGH); //set all pins on the shift register chain to LOW shifter.write(); //send changes to the chain and display them shifter.clear(); shifter.setPin(1, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(3, HIGH); shifter.setPin(5, HIGH); shifter.setPin(7, HIGH); shifter.setPin(9, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(11, HIGH); shifter.setPin(13, HIGH); shifter.setPin(15, HIGH); shifter.setPin(17, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.write(); //send changes to the chain and display them //notice how you only call write after you make all the changes you want to make // delay(7000); shifter.setAll(HIGH); //Set all pins on the chain high shifter.write(); //send changes to the chain and display them delay(1000); } void loop2(){ nixies = 255; // create a blank byte updateShiftRegister(); // send the blank byte to the shift register delay(500); for (x = 0; x<100; x++){ // count from 0 to 99 nixies = charTable[x]; // translate into a byte to send to the shift register updateShiftRegister(); //send to the shift register delay(500); Serial.print("x = "); Serial.println(x); Serial.print("nixies = "); Serial.println(nixies);} } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void displayTime(byte second, byte minute, byte hour) { //byte second, minute, hour; // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; .. 3231 not connected - test 3 byte to shift registers - each for 2 Nixie tube - 2 chip 74141 prints(second); printm(minute); printh(hour); } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void nixieinv (int n, int val) { // use 74141 or not - 10 hv transistors w/ other hex to 10 decimal decoder - inverted switch (val) { case 0: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 1: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 2: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 3: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 4: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 5: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 6: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 7: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 8: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 9: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 10: //off break; } } void nixietrainer() { shifter.clear(); shifter.write(); prints(99); printm(88); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(67); printm(89); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } снимая комментарии выбирается нужный режим работы. Например задержку можно уменьшить до одной десятой секунды.
а так красивше (это проверка ламп) // shifter.setPin(22, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.write();
shifter.clear();
delay(100);
//}
//void looptest(){
// byte second, minute, hour;
for (x = 0; x<100; x++){ // count from 0 to 99
// nixies = charTable[x]; // translate into a byte to send to the shift register
second = x;
minute= x;
hour =x;
//second = second +1;
//minute = minute +1;
//hour = hour +1;
displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141
shifter.write();
delay(200);
}
delay(3000);
shifter.clear();
shifter.write();
delay(100);
весь код – это тест – зажигает семерки и лампы в обратном порядке – все цифры Как только все цифры загораются и хвостики тоже – заменяем 15 Ком на 33КОм к анодам (ИН1) это снизит мощность от батареи с 12 до 4 .. 6 ватт
#include ;
#define SER_Pin 11 //SER_IN //data 14 pin 74hc595
#define RCLK_Pin 12 //L_CLOCK //latch rclk 12 74hc595
#define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595
#define NUM_REGISTERS 3 //how many registers are in the chain
//initaize shifter using the Shifter library
Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS);
// create an array that translates decimal numbers into an appropriate byte for sending to the shift register
int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44,
172,108,236,28,156,2,130,66,194,34,162,98,226,
18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129,
65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153};
byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies
int x; //create a counting variable
byte second = 86;
byte minute = 79;
byte hour = 78;
void setup(){
pinMode(SER_Pin, OUTPUT);
pinMode(RCLK_Pin, OUTPUT);
pinMode(SRCLK_Pin, OUTPUT);
Serial.begin(9600);
}
void loop(){
// byte second, minute, hour;
// shifter.setAll(HIGH);
byte second = 77;
byte minute = 77;
byte hour = 77;
delay(5000);
nixietrainer();
shifter.clear();
shifter.write(); //send changes to the chain and display them
delay(200);
displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141
shifter.write();
delay(5000);
//set all pins on the shift register chain to LOW
// shifter.write(); //send changes to the chain and display them
shifter.clear();
//delay(2000);
shifter.write();
// shifter.setPin(0, LOW); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(1, LOW); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(2, LOW);
shifter.setPin(3, LOW);
// shifter.setPin(4, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(7, LOW); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(19, LOW); //set pin 1 in the chain(second pin) HIGH
// shifter.setPin(14, HIGH); //set pin 1 in the chain(second pin) HIGH
// shifter.setPin(20, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(21, HIGH); //set pin 1 in the chain(second pin) HIGH
// shifter.setPin(22, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.write();
shifter.clear();
delay(100);
//}
//void looptest(){
// byte second, minute, hour;
for (x = 0; x<100; x++){ // count from 0 to 99
// nixies = charTable[x]; // translate into a byte to send to the shift register
second = x;
minute= x-1;
hour =x-2;
//second = second +1;
//minute = minute +1;
//hour = hour +1;
displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141
shifter.write();
delay(200);
displayTime(hour, minute, second); // display the real-time clock data on the Serial Monitor// not use 74141
shifter.write();
delay(200);
}
delay(300);
shifter.clear();
shifter.write();
delay(100);
nixietrainer();
shifter.setAll(HIGH);
//set all pins on the shift register chain to LOW
shifter.write(); //send changes to the chain and display them
shifter.clear();
shifter.setPin(1, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(3, HIGH);
shifter.setPin(5, HIGH);
shifter.setPin(7, HIGH);
shifter.setPin(9, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(11, HIGH);
shifter.setPin(13, HIGH);
shifter.setPin(15, HIGH);
shifter.setPin(17, HIGH); //set pin 1 in the chain(second pin) HIGH
shifter.setPin(19, HIGH);
shifter.setPin(21, HIGH);
shifter.setPin(22, HIGH);
shifter.write(); //send changes to the chain and display them
//notice how you only call write after you make all the changes you want to make
delay(1700);
shifter.setAll(HIGH); //Set all pins on the chain high
shifter.write(); //send changes to the chain and display them
delay(1500);
}
void loop2(){
nixies = 255; // create a blank byte
updateShiftRegister(); // send the blank byte to the shift register
delay(2500);
for (x = 0; x<100; x++){ // count from 0 to 99
nixies = charTable[x]; // translate into a byte to send to the shift register
updateShiftRegister(); //send to the shift register
delay(500);
Serial.print("x = ");
Serial.println(x);
Serial.print("nixies = ");
Serial.println(nixies);}
}
//subs
void updateShiftRegister(){
digitalWrite(RCLK_Pin, LOW);
shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies);
digitalWrite(RCLK_Pin, HIGH);
}
void displayTime(byte second, byte minute, byte hour) {
//byte second, minute, hour;
// retrieve data from DS3231
//readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
// second = 81;
//minute = 98;
//hour = 69;
prints(second);
printm(minute);
printh(hour);
}
// atmega8 basic
//Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3
//Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3
//Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3
//Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3
//Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3
//Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3
void nixie (int n, int val) {
// use 74141
switch (val) {
case 0:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, LOW);
break;
case 1:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, LOW);
break;
case 2:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, LOW);
break;
case 3:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, LOW);
break;
case 4:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 5:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 6:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 7:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 8:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 9:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 10: //off
break;
}
}
void nixieinv (int n, int val) {
// use 74141 or not - 10 hv transistors w/ other hex to 10 decimal decoder - inverted
switch (val) {
case 0:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, HIGH);
break;
case 1:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, HIGH);
break;
case 2:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, HIGH);
break;
case 3:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, HIGH);
break;
case 4:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 5:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 6:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 7:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, LOW);
shifter.setPin(n + 2, LOW);
shifter.setPin(n + 3, HIGH);
break;
case 8:
shifter.setPin(n, HIGH);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 9:
shifter.setPin(n, LOW);
shifter.setPin(n + 1, HIGH);
shifter.setPin(n + 2, HIGH);
shifter.setPin(n + 3, LOW);
break;
case 10: //off
break;
}
}
void nixietrainer() {
shifter.clear();
shifter.write();
prints(00);
printm(00);
printh(00);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(11);
printm(11);
printh(11);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(22);
printm(22);
printh(22);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(33);
printm(33);
printh(33);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(44);
printm(44);
printh(44);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(55);
printm(55);
printh(55);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(66);
printm(66);
printh(66);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(77);
printm(77);
printh(77);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(88);
printm(88);
printh(88);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
prints(99);
printm(99);
printh(99);
shifter.write();
delay(100);
shifter.clear();
shifter.write();
return;
}
void prints(int v) {
int oness;
int tenss;
oness = v % 10;
v = v / 10;
tenss = v % 10;
nixie (20, oness);
nixie (16, tenss);
}
void printm(int m) {
int onesm;
int tensm;
onesm = m % 10;
m = m / 10;
tensm = m % 10;
nixie (12, onesm);
nixie (8, tensm);
}
void printh(int h) {
int onesh;
int tensh;
onesh = h % 10;
h = h / 10;
tensh = h % 10;
nixie (4, onesh);
nixie (0, tensh);
}
а это с помощью простенькой логической операции зажигается цифра 00 90 10 18 0 30 12 14 23 тоже все цифры но с перестановкой разрядов единиц и десятков.
<br> for (x = 0; x<100; x++){ // count from 0 to 99<br><br><span class="crayon-inline lang:arduino decode:true"> // nixies = charTable[x];</span><br><span class="crayon-inline lang:arduino decode:true"> // translate into a byte to send to the shift register<br></span><br><span class="crayon-inline lang:arduino decode:true">second = x;</span><br><span class="crayon-inline lang:arduino decode:true">minute= x-1;</span><br><span class="crayon-inline lang:arduino decode:true">hour =x-2;<br>s1=second % 10;<br>s2=second / 10;<br>m1=minute % 10;<br>m2=minute / 10;<br>h1=hour % 10;<br>h1=hour / 10;<br>//second = second +1;<br>//minute = minute +1;<br>//hour = hour +1;<br> displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor<br>// not use 74141<br> shifter.write();<br> delay(200);<br> hour= h2 || h1;<br> minute= m2 || m1;<br>second= s2 || s1; <br> displayTime(hour, minute, second); // display the real-time clock data on the Serial Monitor<br>// not use 74141<br> shifter.write();<br> delay(200);<br> }</span><br>
варианты для А106 А107 декатрон лампа еще добавлю а103 днем темноват он фиолетовый а ночью нормально видно.
Проверка должна показать что все цифры и лампы работают , на декатроне бегает пружинка. Если это так – включаем амперметр и смотрим – 400 ну 700 миллиампер от 12 вольт , на декатроне 600 перед резистором, на лампах 190- 208, на соединенных катодах декатрона 50 -60 вольт, на микросхемах 4.8 вольта. Подбирается числом витков и делителем у 5 лапы mc34063. авторская работа это БП с эффективностью не меньше 80 85, половина программы и еще мешок декатронов вроде как цельнотянутых даже без коробочек кому не хватило можно принесть пятихатку .. уже похоже больше.
добавляю видео с замедлением декатрона – понять принцип работы и с прожигом ламп . С перебором всех цифр и током до 10 ма от 200 вольт – поставил 15-18 килоом. Мощность выросла до 12 ватт – ток 1 ампер от 12 вольт питания.
проверка всех ламп и эффект на декатроне. Увеличены резисторы, 56к поэтому не полностью возможно светятся цифры, написано здесь как их подобрать.* 2.5 миллиампера рабочий ток, на лампе 200 вольт, на включенной цифре 17 – 30 вольт, на выключенной 60, как ограничивает ИД1. декатрон примерно на 500 герц он не очень скоростной, на нем 600 вольт не на аноде а на резисторе 1,5 Мом конечно . Будет кусочек видео с задержкой полсекунды – как переключается огонек на декатроне – там группа из 3 катодов. Интересно что ночью напряжение зажигания больше чем при ярком свете до полутора раз.
прожигание катодов ламп – этот код проверяет соединения регистры и микросхемы К155ИД1 – для устойчивой работы установлены резисторы 15 – 18 килоом вместо 33 К и при работе потребляемая мощность 12 ватт. Через 10 часов работы горят все хвостики семерок и пятерки которые в лампах не включались. Катоды из молибдена как в декатроне этот прожиг им не навредит. время работы по паспорту можно умножить на 10 а если потом переключить на 33К резисторы то и до 10000 часов не выключаясь. После этого времени понаделают ламп самодельных уже есть примеры. зажигания больше чем при ярком свете до полутора раз. Этот скетч часов требует переделки. Датчик температуры и чип часов подключается к ардуине. Сейчас сниму видео работы декатрона по шагам – это интересно. С украинского завода будет несколько штучек коробков они в картоночках.
- два варианта программы часов ин12
(‘это где больше функций more complex’)
displayTime(hour, minute, second); // display the real-time clock data on the Serial Monitor// not use 74141
shifter.write();
delay(200);<>/pre
Sketch часов чуть выше nixie3.zip с незначительными исправлениями вот это –
#include ;
#include ; // Comes with Arduino IDE
#include ; // Shift 74HC595 // github
#define SER_Pin 11 //SER_IN DS //data 14 pin 74hc595(Serial) Input for the next pin that gets shifted in.
#define RCLK_Pin 12 //L_CLOCK ST //latch rclk 12 74hc595
(Register Clock) Needs to be pulled high to set the output to the new shift register values, This must be pulled high directly after SRCLK has gone LOW again.
#define SRCLK_Pin 8 //CLOCK SH //clock srclk 11 74hc595
(Serial Clock) When this pin is pulled high, it will shift the register.
#define NUM_REGISTERS 3 //how many registers are in the chain
Теперь можно присоединить ds3231 – если часы показывают только нули это не интересно.
пружинка Слинки
threeneurons.wordpress.com
это образец программы еще ** в работе а выше есть по битам какой выберу не определился.
ниже скетч для ардуино почти полностью соответствующий схеме.Очень хрупкие эти регистры – не выдержали скачка по питанию до 7 вольт. Распаиваю их на отдельной платке если что проще менять, еще зачем то коробку в корпусе smd были же обычные.
-- это тоже проверка перебор цифр с 0 до 99 как и мой вариант - если правильно распаяно то на пробирках никси вместо времени 85 74 19 Русалка часы набор. Русалка фыркнула и полезла в ванну. Как там в старом польском журнале - что сказал электрик когда взял проводок о черт ну там 110 вольт он бы по русски сказал если было бы 220. схватил 670 вольт у кондера - оказался надломленый щуп от тестера мастеч. Лучше бы не хватал конечно, а так статья если кому надо разошлась по сетке и даже в архивах. Набор для приготовления электронного оружия у соседа пол телека показывает и в черточках остальное, мобильники сильно греются вместо зарядки, на печке свч горят цифры 99 99 но включается на 99 минут наверно. /* a sketch to drive two nixie tubes using two SN74141 BCD chips and a single SN74HC595N shift register developed from the tutorials on Adafruit.com and arduino.cc the sketch will cause two nixie tubes to count from 0 to 99 but you can change it to create any two-digit number and have the nixie tube display it Jeff Glans 2013 Released into the public domain */ //set up the pins for communication with the shift register int latchPin = 8; int clockPin = 12; int dataPin = 11; int x; //create a counting variable // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies void setup(){ pinMode(latchPin, OUTPUT); pinMode(dataPin, OUTPUT); pinMode(clockPin, OUTPUT); Serial.begin(9600); } void loop(){ nixies = 255; // create a blank byte updateShiftRegister(); // send the blank byte to the shift register delay(500); for (x = 0; x<100; x++){ // count from 0 to 99 nixies = charTable[x]; // translate into a byte to send to the shift register updateShiftRegister(); //send to the shift register delay(500); Serial.print("x = "); Serial.println(x); Serial.print("nixies = "); Serial.println(nixies);} } //the process of sending a byte to the shift register void updateShiftRegister(){ digitalWrite(latchPin, LOW); shiftOut(dataPin, clockPin, LSBFIRST, nixies); digitalWrite(latchPin, HIGH); }
"C:\Arduino\hardware\tools\avr/bin/avr-ar" rcs "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\core\core.a" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\core\new.cpp.o" "C:\Arduino\hardware\tools\avr/bin/avr-gcc" -w -Os -Wl,--gc-sections -mmcu=atmega328p -o "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/in14clock.ino.elf" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\sketch\ClockButton.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\sketch\Transition.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\sketch\in14clock.ino.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\libraries\Wire\Wire.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\libraries\Wire\utility\twi.c.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\libraries\DS3231\DS3231.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\libraries\Time\DateStrings.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp\libraries\Time\Time.cpp.o" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/core\core.a" "-LC:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp" -lm "C:\Arduino\hardware\tools\avr/bin/avr-objcopy" -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/in14clock.ino.elf" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/in14clock.ino.eep" "C:\Arduino\hardware\tools\avr/bin/avr-objcopy" -O ihex -R .eeprom "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/in14clock.ino.elf" "C:\Users\pc-tesla\AppData\Local\Temp\build70ea02bf07901a65382ff209636bb329.tmp/in14clock.ino.hex" Используем библиотеку EEPROM версии 2.0 из папки: C:\Arduino\hardware\arduino\avr\libraries\EEPROM Используем библиотеку Wire версии 1.0 из папки: C:\Arduino\hardware\arduino\avr\libraries\Wire Используем библиотеку DS3231 в папке: C:\Arduino\libraries\DS3231 (legacy) Используем библиотеку Time версии 1.5 из папки: C:\Arduino\libraries\Time Скетч использует 25 796 байт (83%) памяти устройства. Всего доступно 30 720 байт. Глобальные переменные используют 764 байт (37%) динамической памяти, оставляя 1 284 байт для локальных переменных. Максимум: 2048 байт.
---** attach //********************************************************************************** //* Main code for an Arduino based Nixie clock. Features: * //* - Real Time Clock interface for DS3231 * //* - WiFi Clock interface for the WiFiModule * //* - Digit fading with configurable fade length * //* - Digit scrollback with configurable scroll speed * //* - Configuration stored in EEPROM * //* - Low hardware component count (as much as possible done in code) * //* - Single button operation with software debounce * //* - Single K155ID1 for digit display (other versions use 2 or even 6!) * //* - Automatic dimming, using a Light Dependent Resistor * //* - RGB back light management * //* * //* nixie@protonmail.ch * //* * //********************************************************************************** //********************************************************************************** // Standard Libraries #include #include #include #include // Clock specific libraries, install these with "Sketch -> Include Library -> Add .ZIP library // using the ZIP files in the "libraries" directory #include // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) #include // http://playground.arduino.cc/code/time (Margolis 1.5.0) // Other parts of the code, broken out for clarity #include "ClockButton.h" #include "Transition.h" #include "DisplayDefs.h" #include "I2CDefs.h" //********************************************************************************** //********************************************************************************** //* Constants * //********************************************************************************** //********************************************************************************** #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Software version shown in config menu #define SOFTWARE_VERSION 57 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 #define COLOUR_CNL_MAX 15 #define COLOUR_RED_CNL_DEFAULT 15 #define COLOUR_GRN_CNL_DEFAULT 0 #define COLOUR_BLU_CNL_DEFAULT 0 #define COLOUR_CNL_MIN 0 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // Back light #define MODE_BACKLIGHT_MODE 23 // #define MODE_RED_CNL 24 // #define MODE_GRN_CNL 25 // #define MODE_BLU_CNL 26 // #define MODE_CYCLE_SPEED 27 // speed the colour cycle cyles at // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 // RTC address #define RTC_I2C_ADDRESS 0x68 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true //********************************************************************************** //********************************************************************************** //* Variables * //********************************************************************************** //********************************************************************************** // ***** Pin Defintions ****** Pin Defintions ****** Pin Defintions ****** // SN74141/K155ID1 // These are now managed directly on PORT B, we don't use digitalWrite() for these #define ledPin_0_a 13 // package pin 19 // PB5 #define ledPin_0_b 10 // package pin 16 // PB2 #define ledPin_0_c 8 // package pin 14 // PB0 #define ledPin_0_d 12 // package pin 18 // PB4 // anode pins #define ledPin_a_6 0 // low - Secs units // package pin 2 // PD0 #define ledPin_a_5 1 // - Secs tens // package pin 3 // PD1 #define ledPin_a_4 2 // - Mins units // package pin 4 // PD2 #define ledPin_a_3 4 // - Mins tens // package pin 6 // PD4 #define ledPin_a_2 A2 // - Hours units // package pin 25 // PC2 #define ledPin_a_1 A3 // high - Hours tens // package pin 26 // PC3 // button input #define inputPin1 7 // package pin 13 // PD7 // PWM pin used to drive the DC-DC converter #define hvDriverPin 9 // package pin 15 // PB1 // Tick led - PWM capable #define tickLed 11 // package pin 17 // PB3 // PWM capable output for backlight #define RLed 6 // package pin 12 // PD6 #define GLed 5 // package pin 11 // PD5 #define BLed 3 // package pin 5 // PD3 #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; // ************************ Clock variables ************************ // RTC, uses Analogue pins A4 (SDA) and A5 (SCL) DS3231 Clock; // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = false; // true if we detect an RTC byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi // **************************** LED management *************************** boolean upOrDown; // Blinking colons led in settings modes int ledBlinkCtr = 0; int ledBlinkNumber = 0; byte backlightMode = BACKLIGHT_DEFAULT; // Back light intensities byte redCnl = COLOUR_RED_CNL_DEFAULT; byte grnCnl = COLOUR_GRN_CNL_DEFAULT; byte bluCnl = COLOUR_BLU_CNL_DEFAULT; byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; // Back light cycling int colors[3]; int changeSteps = 0; byte currentColour = 0; int impressionsPerSec = 0; int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; //********************************************************************************** //********************************************************************************** //* Setup * //********************************************************************************** //********************************************************************************** void setup() { pinMode(ledPin_0_a, OUTPUT); pinMode(ledPin_0_b, OUTPUT); pinMode(ledPin_0_c, OUTPUT); pinMode(ledPin_0_d, OUTPUT); pinMode(ledPin_a_1, OUTPUT); pinMode(ledPin_a_2, OUTPUT); pinMode(ledPin_a_3, OUTPUT); pinMode(ledPin_a_4, OUTPUT); pinMode(ledPin_a_5, OUTPUT); pinMode(ledPin_a_6, OUTPUT); pinMode(tickLed, OUTPUT); pinMode(RLed, OUTPUT); pinMode(GLed, OUTPUT); pinMode(BLed, OUTPUT); // The LEDS sometimes glow at startup, it annoys me, so turn them completely off analogWrite(tickLed, 0); analogWrite(RLed, 0); analogWrite(GLed, 0); analogWrite(BLed, 0); // NOTE: // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT ); // set the input pin 1 digitalWrite(inputPin1, HIGH); // set pin 1 as a pull up resistor. // Set the driver pin to putput pinMode(hvDriverPin, OUTPUT); /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // Set up timer 2 like timer 0 (for RGB leds) TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); TCCR2B = (1 << CS22); // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } // Read EEPROM values readEEPROMValues(); // set our PWM profile setPWMOnTime(pwmOn); setPWMTopTime(pwmTop); // Set the target voltage rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // HV GOOOO!!!! TCCR1A = tccrOn; if (doTestPattern) { boolean oldUseLDR = useLDR; byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); checkHVVoltage(); setLedsTestPattern(nowMillis); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; blankTubes = false; } } useLDR = oldUseLDR; backlightMode = oldBacklightMode; } // reset the LEDs setLedsTestPattern(0); // Set up the HVG if we need to if (EEPROM.read(EE_HVG_NEED_CALIB)) { calibrateHVG(); // Save the PWM values EEPROM.write(EE_PULSE_LO, pwmOn % 256); EEPROM.write(EE_PULSE_HI, pwmOn / 256); EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); // Mark that we don't need to do this next time EEPROM.write(EE_HVG_NEED_CALIB, false); } // and return it to target voltage so we can regulate the PWM on time rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); setTime(12, 34, 56, 1, 3, 2017); getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } //********************************************************************************** //********************************************************************************** //* Main loop * //********************************************************************************** //********************************************************************************** void loop() { nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; // ------------------------------------------------------------------------------- if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { performOncePerDayProcessing(); } performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // ------------------------------------------------------------------------------- // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs setLeds(); } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage checkHVVoltage(); // feed the watchdog wdt_reset(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) getRTCTime(); } } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } // ************************************************************ // Called once per day // ************************************************************ void performOncePerDayProcessing() { } // ************************************************************ // Set the seconds tick led(s) and the back lights // ************************************************************ void setLeds() { int secsDelta; if (upOrDown) { secsDelta = (nowMillis - lastCheckMillis); } else { secsDelta = 1000 - (nowMillis - lastCheckMillis); } // calculate the PWM factor, goes between minDim% and 100% float dimFactor = (float) digitOffCount / (float) DIGIT_DISPLAY_OFF; float pwmFactor = (float) secsDelta / (float) 1000.0; // Tick led output analogWrite(tickLed, getLEDAdjusted(255, pwmFactor, dimFactor)); if (blankLEDs) { analogWrite(RLed, 0); analogWrite(GLed, 0); analogWrite(BLed, 0); } else { // RGB Backlight PWM led output if (currentMode == MODE_TIME) { switch (backlightMode) { case BACKLIGHT_FIXED: analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], 1, 1)); analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, 1)); analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, 1)); break; case BACKLIGHT_PULSE: analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, 1)); analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, 1)); analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, 1)); break; case BACKLIGHT_CYCLE: cycleColours3(colors); analogWrite(RLed, getLEDAdjusted(colors[0], 1, 1)); analogWrite(GLed, getLEDAdjusted(colors[1], 1, 1)); analogWrite(BLed, getLEDAdjusted(colors[2], 1, 1)); break; case BACKLIGHT_FIXED_DIM: analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], 1, dimFactor)); analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, dimFactor)); analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, dimFactor)); break; case BACKLIGHT_PULSE_DIM: analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, dimFactor)); analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, dimFactor)); analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, dimFactor)); break; case BACKLIGHT_CYCLE_DIM: cycleColours3(colors); analogWrite(RLed, getLEDAdjusted(colors[0], 1, dimFactor)); analogWrite(GLed, getLEDAdjusted(colors[1], 1, dimFactor)); analogWrite(BLed, getLEDAdjusted(colors[2], 1, dimFactor)); break; } } else { // Settings modes ledBlinkCtr++; if (ledBlinkCtr > 40) { ledBlinkCtr = 0; ledBlinkNumber++; if (ledBlinkNumber > nextMode) { // Make a pause ledBlinkNumber = -2; } } if ((ledBlinkNumber <= nextMode) && (ledBlinkNumber > 0)) { if (ledBlinkCtr < 3) { analogWrite(RLed, 255); analogWrite(GLed, 255); analogWrite(BLed, 255); } else { analogWrite(RLed, 0); analogWrite(GLed, 0); analogWrite(BLed, 0); } } } } } // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_BACKLIGHT_MODE: { loadNumberArrayConfInt(backlightMode, displayMode); displayConfig(); break; } case MODE_RED_CNL: { if ((backlightMode == BACKLIGHT_CYCLE) || (backlightMode == BACKLIGHT_CYCLE_DIM)) { // Skip if we are in cycle mode setNewNextMode(MODE_CYCLE_SPEED); } loadNumberArrayConfInt(redCnl, displayMode); displayConfig(); break; } case MODE_GRN_CNL: { loadNumberArrayConfInt(grnCnl, displayMode); displayConfig(); break; } case MODE_BLU_CNL: { loadNumberArrayConfInt(bluCnl, displayMode); displayConfig(); break; } case MODE_CYCLE_SPEED: { if ((backlightMode != BACKLIGHT_CYCLE) && (backlightMode != BACKLIGHT_CYCLE_DIM)) { // Show only if we are in cycle mode setNewNextMode(MODE_TARGET_HV_UP); } loadNumberArrayConfInt(cycleSpeed, displayMode); displayConfig(); break; } case MODE_TARGET_HV_UP: case MODE_TARGET_HV_DOWN: { loadNumberArrayConfInt(hvTargetVoltage, displayMode); displayConfig(); break; } case MODE_PULSE_UP: case MODE_PULSE_DOWN: { loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_VERSION: { loadNumberArrayConfInt(SOFTWARE_VERSION, displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_MODE_VERSION) { loadNumberArrayConfInt(SOFTWARE_VERSION, 0); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_BACKLIGHT_MODE: { if (button1.isButtonPressedAndReleased()) { backlightMode++; if (backlightMode > BACKLIGHT_MAX) { backlightMode = BACKLIGHT_MIN; } } loadNumberArrayConfInt(backlightMode, displayMode); displayConfig(); break; } case MODE_RED_CNL: { if (button1.isButtonPressedAndReleased()) { redCnl++; if (redCnl > COLOUR_CNL_MAX) { redCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(redCnl, displayMode); displayConfig(); break; } case MODE_GRN_CNL: { if (button1.isButtonPressedAndReleased()) { grnCnl++; if (grnCnl > COLOUR_CNL_MAX) { grnCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(grnCnl, displayMode); displayConfig(); break; } case MODE_BLU_CNL: { if (button1.isButtonPressedAndReleased()) { bluCnl++; if (bluCnl > COLOUR_CNL_MAX) { bluCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(bluCnl, displayMode); displayConfig(); break; } case MODE_CYCLE_SPEED: { if (button1.isButtonPressedAndReleased()) { cycleSpeed = cycleSpeed + 2; if (cycleSpeed > CYCLE_SPEED_MAX) { cycleSpeed = CYCLE_SPEED_MIN; } } loadNumberArrayConfInt(cycleSpeed, displayMode); displayConfig(); break; } case MODE_TARGET_HV_UP: { if (button1.isButtonPressedAndReleased()) { hvTargetVoltage += 5; if (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_MIN; } } loadNumberArrayConfInt(hvTargetVoltage, displayMode); rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); displayConfig(); break; } case MODE_TARGET_HV_DOWN: { if (button1.isButtonPressedAndReleased()) { hvTargetVoltage -= 5; if (hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_MAX; } } loadNumberArrayConfInt(hvTargetVoltage, displayMode); rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); displayConfig(); break; } case MODE_PULSE_UP: { if (button1.isButtonPressedAndReleased()) { pwmOn += 10; if (pwmOn > PWM_PULSE_MAX) { pwmOn = PWM_PULSE_MAX; } setPWMOnTime(pwmOn); } loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_PULSE_DOWN: { if (button1.isButtonPressedAndReleased()) { pwmOn -= 10; if (pwmOn > PWM_PULSE_MAX) { pwmOn = PWM_PULSE_MAX; } setPWMOnTime(pwmOn); } loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: { if (button1.isButtonPressedAndReleased()) { antiGhost += 1; if (antiGhost > ANTI_GHOST_MAX) { antiGhost = ANTI_GHOST_MAX; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; } loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_DOWN: { if (button1.isButtonPressedAndReleased()) { antiGhost -= 1; if (antiGhost < ANTI_GHOST_MIN) { antiGhost = ANTI_GHOST_MIN; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; } loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_VERSION: { loadNumberArrayConfInt(SOFTWARE_VERSION, displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } // ************************************************************ // output a PWM LED channel, adjusting for dimming and PWM // brightness: // rawValue: The raw brightness value between 0 - 255 // ledPWMVal: The pwm factor between 0 - 1 // dimFactor: The dimming value between 0 - 1 // ************************************************************ byte getLEDAdjusted(float rawValue, float ledPWMVal, float dimFactor) { byte dimmedPWMVal = (byte)(rawValue * ledPWMVal * dimFactor); return dim_curve[dimmedPWMVal]; } // ************************************************************ // Colour cycling 3: one colour dominates // ************************************************************ void cycleColours3(int colors[3]) { cycleCount++; if (cycleCount > cycleSpeed) { cycleCount = 0; if (changeSteps == 0) { changeSteps = random(256); currentColour = random(3); } changeSteps--; switch (currentColour) { case 0: if (colors[0] < 255) { colors[0]++; if (colors[1] > 0) { colors[1]--; } if (colors[2] > 0) { colors[2]--; } } else { changeSteps = 0; } break; case 1: if (colors[1] < 255) { colors[1]++; if (colors[0] > 0) { colors[0]--; } if (colors[2] > 0) { colors[2]--; } } else { changeSteps = 0; } break; case 2: if (colors[2] < 255) { colors[2]++; if (colors[0] > 0) { colors[0]--; } if (colors[1] > 0) { colors[1]--; } } else { changeSteps = 0; } break; } } } //********************************************************************************** //********************************************************************************** //* Utility functions * //********************************************************************************** //********************************************************************************** // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // ************************************************************ void SetSN74141Chip(int num1) { // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { SetSN74141Chip(NumberArray[i]); } if (timer == digitOffTime) { digitOff(); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // ************************************************************ void digitOn(int digit, int value) { switch (digit) { case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); } SetSN74141Chip(value); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // ************************************************************ void digitOff() { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; } //********************************************************************************** //********************************************************************************** //* RTC Module Time Provider * //********************************************************************************** //********************************************************************************** // ************************************************************ // Get the time from the RTC // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } // Return back to I2C in slave mode Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); Wire.endTransmission(); Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); EEPROM.write(EE_RED_INTENSITY, redCnl); EEPROM.write(EE_GRN_INTENSITY, grnCnl); EEPROM.write(EE_BLU_INTENSITY, bluCnl); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); EEPROM.write(EE_PULSE_LO, pwmOn % 256); EEPROM.write(EE_PULSE_HI, pwmOn / 256); EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } dayBlanking = EEPROM.read(EE_DAY_BLANKING); if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; backlightMode = BACKLIGHT_DEFAULT; redCnl = COLOUR_RED_CNL_DEFAULT; grnCnl = COLOUR_GRN_CNL_DEFAULT; bluCnl = COLOUR_BLU_CNL_DEFAULT; hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; cycleSpeed = CYCLE_SPEED_DEFAULT; pwmOn = PWM_PULSE_DEFAULT; pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; antiGhost = ANTI_GHOST_DEFAULT; useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } //********************************************************************************** //********************************************************************************** //* Light Dependent Resistor * //********************************************************************************** //********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } // ****************************************************************** // Routine to check the PWM LEDs // brightens and dims a PWM capable LED // - 0 to 255 ramp up // - 256 to 511 plateau // - 512 to 767 ramp down // ****************************************************************** void checkLEDPWM(byte LEDPin, int step) { if (step > 767) { analogWrite(LEDPin, getLEDAdjusted(0, 1, 1)); } else if (step > 512) { analogWrite(LEDPin, getLEDAdjusted(255 - (step - 512), 1, 1)); } else if (step > 255) { analogWrite(LEDPin, getLEDAdjusted(255, 1, 1)); } else if (step > 0) { analogWrite(LEDPin, getLEDAdjusted(step, 1, 1)); } } // ****************************************************************** // Calibrate the HV generator // The idea here is to get the right combination of PWM on and top // time to provide the right high voltage with the minimum power // Consumption. // // Every combination of tubes and external power supply is different // and we need to pick the right PWM total duration ("top") and // PWM on time ("on") to match the power supply and tubes. // Once we pick the "on" time, it is not adjusted during run time. // PWM top is adjusted during run. // // The PWM on time is picked so that we reach just the point that the // inductor goes into saturation - any more time on is just being used // to heat the MOSFET and the inductor, but not provide any voltage. // // We go through two cycles: each time we decrease the PWM top // (increase frequency) to give more voltage, then reduce PWM on // until we notice a drop in voltage. // ****************************************************************** void calibrateHVG() { // *************** first pass - get approximate frequency ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage + 5); setPWMOnTime(PWM_PULSE_DEFAULT); // Calibrate HVGen at full for (int i = 0 ; i < 768 ; i++ ) { loadNumberArraySameValue(8); allBright(); outputDisplay(); checkHVVoltage(); checkLEDPWM(tickLed, i); } // *************** second pass - get on time minimum ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // run up the on time from the minimum to where we reach the required voltage setPWMOnTime(PWM_PULSE_MIN); for (int i = 0 ; i < 768 ; i++ ) { //loadNumberArray8s(); loadNumberArrayConfInt(pwmOn, 0); allBright(); outputDisplay(); if (getSmoothedHVSensorReading() < rawHVADCThreshold) { if ((i % 8) == 0 ) { incPWMOnTime(); } } checkLEDPWM(RLed, i); } int bottomOnValue = pwmOn; // *************** third pass - get on time maximum ************* setPWMOnTime(pwmOn + 50); for (int i = 0 ; i < 768 ; i++ ) { //loadNumberArray8s(); loadNumberArrayConfInt(pwmOn, 0); allBright(); outputDisplay(); if (getSmoothedHVSensorReading() > rawHVADCThreshold) { if ((i % 8) == 0 ) { decPWMOnTime(); } } checkLEDPWM(GLed, i); } int topOnValue = pwmOn; int aveOnValue = (bottomOnValue + topOnValue) / 2; setPWMOnTime(aveOnValue); // *************** fourth pass - adjust the frequency ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage + 5); // Calibrate HVGen at full for (int i = 0 ; i < 768 ; i++ ) { loadNumberArraySameValue(8); allBright(); outputDisplay(); checkHVVoltage(); checkLEDPWM(BLed, i); } } /** Set the PWM top time. Bounds check it so that it stays between the defined minimum and maximum, and that it does not go under the PWM On time (plus a safety margin). Set both the internal "pwmTop" value and the register. */ void setPWMTopTime(int newTopTime) { if (newTopTime < PWM_TOP_MIN) { newTopTime = PWM_TOP_MIN; } if (newTopTime > PWM_TOP_MAX) { newTopTime = PWM_TOP_MAX; } if (newTopTime < (pwmOn + PWM_OFF_MIN)) { newTopTime = pwmOn + PWM_OFF_MIN; } ICR1 = newTopTime; pwmTop = newTopTime; } /** Set the new PWM on time. Bounds check it to make sure that is stays between pulse min and max, and that it does not get bigger than PWM top, less the safety margin. Set both the internal "pwmOn" value and the register. */ void setPWMOnTime(int newOnTime) { if (newOnTime < PWM_PULSE_MIN) { newOnTime = PWM_PULSE_MIN; } if (newOnTime > PWM_PULSE_MAX) { newOnTime = PWM_PULSE_MAX; } if (newOnTime > (pwmTop - PWM_OFF_MIN)) { newOnTime = pwmTop - PWM_OFF_MIN; } OCR1A = newOnTime; pwmOn = newOnTime; } void incPWMOnTime() { setPWMOnTime(pwmOn + 1); } void decPWMOnTime() { setPWMOnTime(pwmOn - 1); } /** Get the HV sensor reading. Smooth it using a simple moving average calculation. */ int getSmoothedHVSensorReading() { int rawSensorVal = analogRead(sensorPin); double sensorDiff = rawSensorVal - sensorHVSmoothed; sensorHVSmoothed += (sensorDiff / sensorSmoothCountHV); int sensorHVSmoothedInt = (int) sensorHVSmoothed; return sensorHVSmoothedInt; } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps; configArray[idx++] = backlightMode; configArray[idx++] = redCnl; configArray[idx++] = grnCnl; configArray[idx++] = bluCnl; configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } transition /** * A class that displays a message by scrolling it into and out of the display * * Thanks judge! */ #include "Arduino.h" #include "Transition.h" Transition::Transition(int effectInDuration, int effectOutDuration, int holdDuration) { _effectInDuration = effectInDuration; _effectOutDuration = effectOutDuration; _holdDuration = holdDuration; _started = 0; _end = 0; } void Transition::start(unsigned long now) { if (_end < now) { _started = now; _end = getEnd(); saveCurrentDisplayType(); } // else we are already running! } boolean Transition::isMessageOnDisplay(unsigned long now) { return (now < _end); } // we need to get the seconds updated, otherwise we show the old // time at the end of the stunt void Transition::updateRegularDisplaySeconds(int seconds) { _regularDisplay[5] = seconds % 10; _regularDisplay[4] = seconds / 10; } boolean Transition::scrollMsg(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); // Scroll -1 -> -DIGIT_COUNT scroll(-(msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration - 1); } else if (msCount < _effectInDuration * 2) { loadAlternateValues(); // Scroll (DIGIT_COUNT-1) -> 0 scroll((DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); // Scroll 1 -> DIGIT_COUNT scroll(((msCount - _holdDuration) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); // Scroll 0 -> -(DIGIT_COUNT-1) scroll(((msCount - _holdDuration) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration - (DIGIT_COUNT-1)); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } boolean Transition::scrambleMsg(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); scramble(msCount, (DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration, DIGIT_COUNT); } else if (msCount < _effectInDuration * 2) { loadAlternateValues(); scramble(msCount, 0, (DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); scramble(msCount, 0, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); scramble(msCount, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1, DIGIT_COUNT); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } boolean Transition::scrollInScrambleOut(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); scroll(-(msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration - 1); } else if (msCount < _effectInDuration * 2) { restoreCurrentDisplayType(); loadAlternateValues(); scroll((DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); scramble(msCount, 0, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); scramble(msCount, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1, DIGIT_COUNT); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } /** * +ve scroll right * -ve scroll left */ int Transition::scroll(int8_t count) { byte copy[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; memcpy(copy, NumberArray, sizeof(copy)); int8_t offset = 0; int8_t slope = 1; if (count < 0) { count = -count; offset = (DIGIT_COUNT-1); slope = -1; } for (byte i=0; i<digit_count; i++)="" {="" if="" (i="" <="" count)="" displaytype[offset="" +="" i="" *="" slope]="BLANKED;" }="">= count) { NumberArray[offset + i * slope] = copy[offset + (i-count) * slope]; } } return count; } unsigned long Transition::hash(unsigned long x) { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return x; } // In these functions we want something that changes quickly // hence msCount/20. Plus it needs to be different for different // indices, hence +i. Plus it needs to be 'random', hence hash function int Transition::scramble(int msCount, byte start, byte end) { for (int i=start; i < end; i++) { NumberArray[i] = hash(msCount / 20 + i) % 10; } return start; } void Transition::setRegularValues() { memcpy(_regularDisplay, NumberArray, sizeof(_regularDisplay)); } void Transition::setAlternateValues() { memcpy(_alternateDisplay, NumberArray, sizeof(_alternateDisplay)); } void Transition::loadRegularValues() { memcpy(NumberArray, _regularDisplay, sizeof(_regularDisplay)); } void Transition::loadAlternateValues() { memcpy(NumberArray, _alternateDisplay, sizeof(_alternateDisplay)); } void Transition::saveCurrentDisplayType() { memcpy(_savedDisplayType, displayType, sizeof(_savedDisplayType)); _savedScrollback = scrollback; scrollback = false; } void Transition::restoreCurrentDisplayType() { memcpy(displayType, _savedDisplayType, sizeof(_savedDisplayType)); scrollback = _savedScrollback; } unsigned long Transition::getEnd() { return _started + _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2; } transition h #ifndef Transition_h #define Transition_h #include "Arduino.h" #include "DisplayDefs.h" extern byte NumberArray[]; extern byte displayType[]; extern boolean scrollback; class Transition { public: Transition(int, int, int); void start(unsigned long); boolean isMessageOnDisplay(unsigned long); void updateRegularDisplaySeconds(int seconds); boolean scrollMsg(unsigned long); boolean scrambleMsg(unsigned long); boolean scrollInScrambleOut(unsigned long); void setRegularValues(); void setAlternateValues(); void loadRegularValues(); void loadAlternateValues(); void saveCurrentDisplayType(); void restoreCurrentDisplayType(); private: int _effectInDuration; int _effectOutDuration; int _holdDuration; unsigned long _started; unsigned long _end; byte _regularDisplay[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; byte _alternateDisplay[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; boolean _savedScrollback; byte _savedDisplayType[DIGIT_COUNT] = {FADE, FADE, FADE, FADE, FADE, FADE}; unsigned long getEnd(); int scroll(int8_t); int scramble(int, byte, byte); unsigned long hash(unsigned long); }; #endif clock button #include "Arduino.h" #include "ClockButton.h" ClockButton::ClockButton(int inputPin, boolean activeLow) { pinMode(inputPin, OUTPUT); _inputPin = inputPin; _activeLow = activeLow; } // ************************************************************ // MAIN BUTTON CHECK ENTRY POINT - should be called periodically // See if the button was pressed and debounce. We perform a // sort of preview here, then confirm by releasing. We track // 3 lengths of button press: momentarily, 1S and 2S. // ************************************************************ void ClockButton::checkButton(unsigned long nowMillis) { checkButtonInternal(nowMillis); } // ************************************************************ // Reset everything // ************************************************************ void ClockButton::reset() { resetInternal(); } // ************************************************************ // Check if button is pressed right now (just debounce) // ************************************************************ boolean ClockButton::isButtonPressedNow() { return button1PressedCount == debounceCounter; } // ************************************************************ // Check if button is pressed momentarily // ************************************************************ boolean ClockButton::isButtonPressed() { return buttonPress; } // ************************************************************ // Check if button is pressed for a long time (> 1S) // ************************************************************ boolean ClockButton::isButtonPressed1S() { return buttonPress1S; } // ************************************************************ // Check if button is pressed for a moderately long time (> 2S) // ************************************************************ boolean ClockButton::isButtonPressed2S() { return buttonPress2S; } // ************************************************************ // Check if button is pressed for a very long time (> 8S) // ************************************************************ boolean ClockButton::isButtonPressed8S() { return buttonPress8S; } // ************************************************************ // Check if button is pressed for a short time (> 200mS) and released // ************************************************************ boolean ClockButton::isButtonPressedAndReleased() { if (buttonPressRelease) { buttonPressRelease = false; return true; } else { return false; } } // ************************************************************ // Check if button is pressed for a long time (> 2) and released // ************************************************************ boolean ClockButton::isButtonPressedReleased1S() { if (buttonPressRelease1S) { buttonPressRelease1S = false; return true; } else { return false; } } // ************************************************************ // Check if button is pressed for a very moderately time (> 2) and released // ************************************************************ boolean ClockButton::isButtonPressedReleased2S() { if (buttonPressRelease2S) { buttonPressRelease2S = false; return true; } else { return false; } } // ************************************************************ // Check if button is pressed for a very long time (> 8) and released // ************************************************************ boolean ClockButton::isButtonPressedReleased8S() { if (buttonPressRelease8S) { buttonPressRelease8S = false; return true; } else { return false; } } void ClockButton::checkButtonInternal(unsigned long nowMillis) { if (digitalRead(_inputPin) == 0) { buttonWasReleased = false; // We need consecutive pressed counts to treat this is pressed if (button1PressedCount < debounceCounter) { button1PressedCount += 1; // If we reach the debounce point, mark the start time if (button1PressedCount == debounceCounter) { button1PressStartMillis = nowMillis; } } else { // We are pressed and held, maintain the press states if ((nowMillis - button1PressStartMillis) > 8000) { buttonPress8S = true; buttonPress2S = true; buttonPress1S = true; buttonPress = true; } else if ((nowMillis - button1PressStartMillis) > 2000) { buttonPress8S = false; buttonPress2S = true; buttonPress1S = true; buttonPress = true; } else if ((nowMillis - button1PressStartMillis) > 1000) { buttonPress8S = false; buttonPress2S = false; buttonPress1S = true; buttonPress = true; } else { buttonPress8S = false; buttonPress2S = false; buttonPress1S = false; buttonPress = true; } } } else { // mark this as a press and release if we were pressed for less than a long press if (button1PressedCount == debounceCounter) { buttonWasReleased = true; buttonPressRelease8S = false; buttonPressRelease2S = false; buttonPressRelease1S = false; buttonPressRelease = false; if (buttonPress8S) { buttonPressRelease8S = true; } else if (buttonPress2S) { buttonPressRelease2S = true; } else if (buttonPress1S) { buttonPressRelease1S = true; } else if (buttonPress) { buttonPressRelease = true; } } // Reset the switch flags debounce counter buttonPress8S = false; buttonPress2S = false; buttonPress1S = false; buttonPress = false; button1PressedCount = 0; } } void ClockButton::resetInternal() { buttonPressRelease8S = false; buttonPressRelease2S = false; buttonPressRelease1S = false; buttonPressRelease = false; buttonPress8S = false; buttonPress2S = false; buttonPress1S = false; buttonPress = false; button1PressedCount = 0; } clock button h #ifndef ClockButton_h #define ClockButton_h #include "Arduino.h" class ClockButton { public: ClockButton(int inputPin, boolean activeLow); void checkButton(unsigned long nowMillis); void reset(); boolean isButtonPressedNow(); boolean isButtonPressed(); boolean isButtonPressed1S(); boolean isButtonPressed2S(); boolean isButtonPressed8S(); boolean isButtonPressedAndReleased(); boolean isButtonPressedReleased1S(); boolean isButtonPressedReleased2S(); boolean isButtonPressedReleased8S(); private: int _inputPin; boolean _activeLow; void checkButtonInternal(unsigned long nowMillis); void resetInternal(); int button1PressedCount = 0; unsigned long button1PressStartMillis = 0; const byte debounceCounter = 5; // Number of successive reads before we say the switch is down boolean buttonWasReleased = false; boolean buttonPress8S = false; boolean buttonPress2S = false; boolean buttonPress1S = false; boolean buttonPress = false; boolean buttonPressRelease8S = false; boolean buttonPressRelease2S = false; boolean buttonPressRelease1S = false; boolean buttonPressRelease = false; }; #endif #ifndef DisplayDefs_h #define DisplayDefs_h // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // ************************************************************ // LED brightness correction: The perceived brightness is not linear // ************************************************************ const byte dim_curve[] = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, }; const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 #endif i2c defs #ifndef I2CDefs_h #define I2CDefs_h // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #endif ##digit_count;timelib.h ds3231.h avr wire.h eeprom.h avr
Видео будет ночью. И в пещере..
весь каталог arduino во вложениях , библиотеки Shifter и на что там еще ругается при сборке – компилировании взяты с github добавлю сюда . https://github.com/Simsso/ShiftRegister74HC595 https://github.com/PaulStoffregen/TimerOne TimerOne использует декатрон. Bounce для кнопочек часов https://playground.arduino.cc/Code/Bounce/ там уже убежала во вложениях bounce bounce2 ShiftOut сразу вывод цифр а не по битам.
Схема индикаторов вот отсюда только у меня проводки к цифрам по – другому немножко. Поленился нарисовать в редакторе. или нужен карандаш зеленая и красная ручки и лист бумаги.
про источник и вч транс – hi-pot чуть выше . 600 200 и 5 вольт на одной катушечке, питание от 12 вольт 400-700 мА то есть 6 – 8 ватт при всех 7 работающих лампах . При проверке логики с высоким но без ламп 300 миллиампер. Это к рассчету батареи – питание будет батарейное ну конечно от лития 4s24p. (вместо батареи за 200 долларов из lg hg2 вполне подойдет 800 ма блок питания от Сеги, с ним и проверялось, будут работать в помещении без электрики где такие помещения смотрим другие записи на сайте.. )

проверил блок на 20 ватт .. случайно – оторвалась проволочка от 600 вольт и резистора 1200 к и к 5 выводу MC34063 – там на землю резистор 2 .. 3 килоом 3,32 . Теперь подбираю лучший режим работы вот этим резистором. Как выяснилось на практике – схема работает при 3 с половиной вольтах, анодные по 10килоом, и на лампах 140 вольт, мощность меньше 5 ватт, и до 6.1 вольта, что конечно не сильно хорошо для микросхем, мощность 24 ватта, анодное декатрона 670 вольт, на лампах питание 240 вольт. Начинают зажигаться все катоды если выключить дешифратор, засветка потому что 60 вольт ограничивает ИД1 а оставшихся 180 вольт достаточно для зажигания ламп. (Устанавливаю ровно 200 вольт – как показывает практика, при 140 чуть чуть только свечение – это для ИН1). при общей нагрузке 24 ватта источник почти не греется – питание от 12 вольт. Здесь ограничение по импульсам тока полевика (2)н а 3.5 умножить будет 7 ампер, насыщению сердечника сколько то ампер на метр, и по сопротивлению и соответственно падению напряжения на обмотке, в рассчете фонаря от 3 вольт получается с 1 транзисторов на 50 ампер и 70 миллиом только 6 ватт.. тут полегче режим. Регулировку яркости за счет напряжения питания делать точно не надо.

подбор режима работы 430pf 3.32 кОм (3.9 = 24) второе плечо 1.22 мегом соответственно 1.25 вольт будет при 570 вольтах на выходе. от отвода снимается 169- 180 вольт. По цепи 5 вольт полтора витка дают 4.52 вольта что в самый раз (работает все начиная от 3.6 вольта). Мощность 6 – 12 ватт с анодными резисторами 12 и 18 килоом = потом их увеличу до примерно 24к. частота чуть больше 100 килогерц импульс тока полевика до 3 ампер максимум, время закрывания 250 наносекунд – стоит усилитель на кт361 – кт315 от 12 вольт – комплементарная пара эмиттерный повторитель. Ток в цепи затвора 1.4 ампера до 200 нс. (на включение это допустимый ток для 34063, разряжается емкость перехода через кт361 что с запасом в 3 раза по импульсному току). Чуть более расписано в рассчете Фонарик на светодиоде.
ремонт – менял 2 регистра и 1 ИД1 повидимому высокое попало. Для ремонта очень помогает фонарь = на другой страничке описание, он 6 ватт светодиодный, на половину яркости конечно, тот вариант где 56 светодиодов, как лампа хирургическая прямо. При 180 засветка даже при полностью выключенном дешифраторе – код 15 – полностью отсутствует (при 190 вольтах есть совсем немножко, а если 240 то каж ется что этот ИД1 пробился и его надо менять. Если надо напряжение выше – вариант только поставить 10 высоковольтных транзисторов после или даже вместо К155ИД1. * не надо – ИД1 справляется при 170 никакой засветки нет и чуть чуть при 190, это статика.)
proverka raspaiki i numeracii код для проверки правильности соединений и всех регистров с дешифраторами установка напряжений при проверке 4 155 430 вольт byte second = 19 ; byte minute = 74; byte hour = 86; //delay(5000); displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor // use 74141 shifter.write(); // connection , 3 registers , 6 hv decoders dest - 74141 or K155ID1 delay(5000); second = 77; minute = 77; hour = 77; //delay(5000); displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor // use 74141 shifter.write(); delay(5000);
86 74 19 показывает – все соединения верные. почему то цифра секунд гаснет с задержкой в секунды 3.. особенность дешифратора кажется.
поехали дальше . Все лампочки горят цифры прожглись немножко – декатрон крутится , – видео вот-
(ну вот блин я его 3 часа восстанавливал – надо то было регистр поменять и дешифратор, залить термоклеем соединения где высокое советую. И щупы от тестера проверить не надломились ли – а чего это он так дербалызнул шо искры из глаз я же его не бил.. так там киловольт почти и с емкости еще. Осторожнее – студентов похожая штука поубивала в 1959-м со слов отца). Надеть перчатки и настраивать в сухом помещении тогда опасности нет. Высоковольтную часть после настройки можно залить термоклеем – прозрачным который палочки для пистолета.
еще короткий повтор (__ )






нашел сборку резисторов 562 то есть 5600 ом это тоже подходит а установка адреса 24c32 вс единички то есть соединить с резисторами и к плюсу.
если сомнения что i2c надо на A4 A5 подключать то смотрю библиотеку (two)Wire она в каталоге ардуино вот она чуть ниже
и не покупал модули пакетик микросхем на ту же денежку даже в чип и дип да еще нашел резисторы. Батарейку паять нельзя но можно к ней гнездо – на Митино есть много где.
Теперь немного о самом модуле, построен он на микросхеме DS3231N. Резисторная сборка RP1 (4.7 кОм), необходима для подтяжки линий 32K, SQW, SCL и SDA (кстати, если используется несколько модулей с шиной I2C, необходимо выпаять подтягивающие резисторы на других модулях). Вторая сборка резисторов, необходима для подтяжки линий A0, A1 и A2, необходимы они для смены адресации микросхемы памяти AT24C32N. Резистор R5 и диод D1, служат для подзарядки батарее, в принципе их можно выпаять, так как обычной батарейки SR2032 хватает на годы. Так же установлена микросхема памяти AT24C32N, это как бы бонус, для работы часов RTC DS3231N в ней нет необходимости. Резистор R1 и светодиод Power, сигнализируют о включении модуля. Как и говорилось, модуль работает по шине I2C, для удобства эти шины были выведены на два разъема J1 и J2, назначение остальных контактов, можно посмотреть ниже.Назначение J1
> 32K: выход, частота 32 кГц
> SQW: выход
> SCL: линия тактирования (Serial CLock)
> SDA: линия данных (Serial Dфta)
> VCC: «+» питание модуля
> GND: «-» питание модуля Назначение J2
> SCL: линия тактирования (Serial CLock)
> SDA: линия данных (Serial Data)
> VCC: «+» питание модуля
> GND: «-» питание модуля
This library allows you to communicate with I2C / TWI devices. On the Arduino boards with the R3 layout (1.0 pinout), the SDA (data line) and SCL (clock line) are on the pin headers close to the AREF pin. The Arduino Due has two I2C / TWI interfaces SDA1 and SCL1 are near to the AREF pin and the additional one is on pins 20 and 21. As a reference the table below shows where TWI pins are located on various Arduino boards. BoardI2C / TWI pins Uno, EthernetA4 (SDA), A5 (SCL) Mega256020 (SDA), 21 (SCL) Leonardo2 (SDA), 3 (SCL) Due20 (SDA), 21 (SCL), SDA1, SCL1 As of Arduino 1.0, the library inherits from the Stream functions, making it consistent with other read/write libraries. Because of this, send() and receive() have been replaced with read() and write(). Note There are both 7- and 8-bit versions of I2C addresses. 7 bits identify the device, and the eighth bit determines if it’s being written to or read from. The Wire library uses 7 bit addresses throughout. If you have a datasheet or sample code that uses 8 bit address, you’ll want to drop the low bit (i.e. shift the value one bit to the right), yielding an address between 0 and 127. However the addresses from 0 to 7 are not used because are reserved so the first address that can be used is 8. Please note that a pull-up resistor is needed when connecting SDA/SCL pins. Please refer to the examples for more informations. MEGA 2560 board has pull-up resistors on pins 20 – 21 onboard.
The Wire library implementation uses a 32 byte buffer, therefore any communication should be within this limit. Exceeding bytes in a single transmission will just be dropped.
To use this library#include <Wire.h>
то есть sda scl занимают лапы A4 A5 у маленькой ардуинки

как видно на фото подтягивающие резисторы 4k7 а установка адреса елли нужно – нулевыми то есть перемычками
Немного расскажу, о микросхеме AT24C32N, это микросхема с 32к памятью (EEPROM) от производителя Atmel, собранная в корпусе SOIC8, работающая по двухпроводной шине I2C. Адрес микросхемы 0x57, при необходимости легко меняется, с помощью перемычек A0, A1 и A2 (это позволяет увеличить количество подключенных микросхем AT24C32/64). Так как чип AT24C32N имеет, три адресных входа (A0, A1 и A2), которые могут находится в двух состояния, либо лог «1» или лог «0», микросхеме доступны восемь адресов. от 0x50 до 0x57.
Подключение DS3231 к Arduino
Необходимые детали:
> Arduino UNO R3 x 1 шт. * десяток они часто горят хотя если в 220 не включать..
> Часы реального времени на DS3231, RTC, SPI, AT24C32 x 1 шт.
> Провод DuPont, 2,54 мм, 20 см, F-M (Female — Male) x 1 шт.
> Кабель USB 2.0 A-B x 1 шт.
Подключение:
В данном примере буду использовать только модуль DS3231 и Arduino UNO R3, все данные будут передаваться в «Мониторинг порта». Схема не сложная, необходимо всего четыре провода, сначала подключаем шину I2C, SCL в A4 (Arduino UNO) и SDA в A5 (Arduino UNO), осталось подключить питание GND к GND и VCC к 5V (можно записать и от 3.3В), схема собрана, теперь надо подготовить программную часть.


Библиотеки работающий с DS3231 нет в среде разработке IDE Arduino, необходимо скачать «DS3231 » и добавить в среду разработки Arduino.
Установка времени DS3231
При первом включении необходимо запрограммировать время, откройте пример из библиотеки DS3231 «Файл» —> «Примеры» —> «DS3231» —> «Arduino» —> «DS3231_Serial_Easy», или скопируйте код снизу /* Тестирование производилось на Arduino IDE 1.8.0 Дата тестирования 31.08.2018г. */ #include <DS3231.h> // Подключаем библиотеку Wire DS3231 rtc(SDA, SCL); // Инициализация DS3231 void setup() { Serial.begin(115200); // Установка последовательного соединения rtc.begin(); // Инициализировать rtc // Установка времени rtc.setDOW(FRIDAY); // Установить день-недели rtc.setTime(16, 29, 0); // Установить время 16:29:00 (формат 24 часа) rtc.setDate(31, 8, 2018); // Установить дату 31 августа 2018 года } void loop() { Serial.print(rtc.getDOWStr()); // Отправляем день-неделя Serial.print(” “); Serial.print(rtc.getDateStr()); // Отправляем дату Serial.print(” — “); Serial.println(rtc.getTimeStr()); // Отправляем время delay (1000); // Задержка в одну секунду }
123456789101112131415161718192021222324252627282930 | /* Тестирование производилось на Arduino IDE 1.8.0 Дата тестирования 31.08.2018г.*/ #include <DS3231.h> // Подключаем библиотеку Wire DS3231 rtc(SDA, SCL); // Инициализация DS3231 void setup(){ Serial.begin(115200); // Установка последовательного соединения rtc.begin(); // Инициализировать rtc // Установка времени rtc.setDOW(FRIDAY); // Установить день-недели rtc.setTime(16, 29, 0); // Установить время 16:29:00 (формат 24 часа) rtc.setDate(31, 8, 2018); // Установить дату 31 августа 2018 года}void loop(){ Serial.print(rtc.getDOWStr()); // Отправляем день-неделя Serial.print(” “); Serial.print(rtc.getDateStr()); // Отправляем дату Serial.print(” — “); Serial.println(rtc.getTimeStr()); // Отправляем время delay (1000); // Задержка в одну секунду} |
Загружаем скетч в контроллер Arduino и открываем «Мониторинг порта»
#include <Wire.h>
#include <ds3231.h>
struct ts t;
void setup() {
Serial.begin(9600);
Wire.begin();
DS3231_init(DS3231_CONTROL_INTCN);
/*----------------------------------------------------------------------------
In order to synchronise your clock module, insert timetable values below !
----------------------------------------------------------------------------*/
t.hour=12;
t.min=30;
t.sec=0;
t.mday=25;
t.mon=12;
t.year=2019;
DS3231_set(t);
}
void loop() {
DS3231_get(&t);
Serial.print("Date : ");
Serial.print(t.mday);
Serial.print("/");
Serial.print(t.mon);
Serial.print("/");
Serial.print(t.year);
Serial.print("\t Hour : ");
Serial.print(t.hour);
Serial.print(":");
Serial.print(t.min);
Serial.print(".");
Serial.println(t.sec);
delay(1000);
}
Библиотека для DS3231 и будильники (на потом)
Я использую библиотеку https://github.com/jarzebski/Arduino-DS3231, она поддерживает все функции DS3231 и не требует установки других библиотек. Предлагаю и вам скачать данную библиотеку и добавить её в среду разработки Ардуино. В ней есть несколько полезных примеров. Для сейчас интересует пример DS3231_intalarm, показывающий, как установить будильник и генерировать им внешнее прерывание. Правда в примере раскрыты не все опции библиотеки, поэтому я немного подправил его и привел ниже для рассмотрения. Залейте его в Ардуино и откройте монитор порта. Модуль DS3231 должен быть подключен к Ардуино по приведённой выше схеме.
#include <Wire.h> #include <DS3231.h> DS3231 clock; volatile boolean isAlarm = false; void alarmFunction() { isAlarm = true; } void setup() { Serial.begin(9600); // Инициализация RTC, сброс будильников clock.begin(); clock.enableOutput(false); // INT/SQW используем для генерации прерываний clock.armAlarm1(false); // Запрещаем прерывания от будильников clock.armAlarm2(false); clock.clearAlarm1(); // Сбрасываем флаги будильников clock.clearAlarm2(); // Выставляем время clock.setDateTime(__DATE__, __TIME__); // Используем время компиляции //clock.setDateTime(2020, 9, 11, 12, 0, 0); // Выставляем время вручную: 11.09.2020 12:00:00 // Выставляем будильник 1 //clock.setAlarm1(0, 0, 0, 0, DS3231_EVERY_SECOND); // Сигнал каждую секунду clock.setAlarm1(0, 0, 0, 20, DS3231_MATCH_S); // Сигнал в 20 секунд каждой минуты //clock.setAlarm1(0, 0, 30, 20, DS3231_MATCH_M_S); // Сигнал в 30 минут и 20 секунд каждого часа //clock.setAlarm1(0, 12, 30, 20, DS3231_MATCH_H_M_S); // Сигнал ежедневно в 12:30:20 //clock.setAlarm1(10, 12, 30, 20, DS3231_MATCH_DT_H_M_S); // Сигнал 10 числа в 12:30:20 //clock.setAlarm1(4, 12, 30, 20, DS3231_MATCH_DY_H_M_S); // Сигнал по четвергам в 12:30:20 // Выставляем будильник 2 clock.setAlarm2(0, 0, 0, DS3231_EVERY_MINUTE); // Сигнал каждую минуту //clock.setAlarm2(0, 0, 30, DS3231_MATCH_M); // Сигнал в 30 минут каждого часа //clock.setAlarm2(0, 12, 30, DS3231_MATCH_H_M); // Сигнал каждый день в 12:30:00 //clock.setAlarm2(10, 12, 30, DS3231_MATCH_DT_H_M); // Сигнал 10 числа в 12:30:00 //clock.setAlarm2(10, 12, 30, DS3231_MATCH_DT_H_M); // Сигнал 10 числа в 12:30:00 //clock.setAlarm2(4, 12, 30, DS3231_MATCH_DY_H_M); // Сигнал по четвергам в 12:30:00 // Разрешаем внешнее прерывание по сигналу будильника pinMode(2, INPUT_PULLUP); // Вход нужно подтянуть к питанию attachInterrupt(0, alarmFunction, FALLING); // Разрешаем прерывание } void loop() { RTCDateTime dt = clock.getDateTime(); // Получаем текущее время Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt)); // Выводим его в Serial if (isAlarm) { // Сработал будильник isAlarm = false; // Если задействованы оба будильника, то нужна проверка, какой из них сработал if (clock.isAlarm1()) { // Сработал первый будильник clock.clearAlarm1(); Serial.println("*** Alarm 1 ***"); } if (clock.isAlarm2()) { // Сработал второй будильник clock.clearAlarm2(); Serial.println("*** Alarm 2 ***"); } } delay(1000); }
А лучше вывести 31 08 18 подождать 3 секунды и потом 16 29 00 16 29 01 и 5 секунд или 7 – 16 29 05 16 29 07 погасить на секунду и опять число месяц год и 5 – 7 10 секунд время, и не нажимать кнопок просто так ( кнопки установка выбор + – установка опять) – щас будет программа. у кого есть похожая или написали сами – бросайте в коммент . И кнопку не надо нажимать чтобы число и время вывести . Это и будет основная программа часов . Правильный алгоритм это девять десятых программы.
пример алгоритма – робот охраняет участок
(комар ) лазер к бою .. пшшш
(свой) .. (ничего не делаем)
(чужой) .. “315% _*? ” (материмся патрон нет)
надо открыть вольер с караульной собакой ес _ (кончилась память)
(ошибка сенсора) .. Извиняюс.т

Ссылки Библиотека libraries-DS3231
https://github.com/jarzebski/Arduino-DS3231
ставим ds3231 и кнопочки для установки времени и добавляем их програмку в скетч.
автор источника питания пишет эту статью Не программы – она из разных кусочков собрана, хотя есть и мои вставочки. На этой странице больше обьясняется принцип работы. Вот например по кнопкам – как соединить 5 кнопок на один вход аналоговый у Ардуино A0 arduino 5 – button input 100k с питания 5 вольт и на землю от A0 5 резисторов на картинке – 10 килоом 5 3 2 и 1 (забыли в описании.. но по цветам понятно ) и вот к этому подключению программа… комментирую моргание светодиодами и уточнить что считывается от 50 милливольт до полвольта. j;yj edtkbxbnm ‘nj

//Michael Klements //The DIY Life //17 May 2019 //Santosha - use within 500ms cycle - read which buttons pressed // i think a resistor values 100k to +5v and connect to A0 input (first leg) from 5 buttons, 10k 5k 3k // 2k 1k from second leg of button to ground, voltage 50mv (100k-1k) to 500 mv (100k-10k) // 100k to ground . read input value then display as time to nixies. int ledPin = 13; // choose the pin for the LED int buttonValue = 0; void setup() { pinMode(ledPin, OUTPUT); // declare LED as output } void loop() { //... pushbutton() //.. } //.. void pushbutton (byte *button1, byte *button2, byte *button3, byte *button4, byte *button5) { button1=0; button2=0; //.. buttonValue = analogRead(A0); //Read in the button value CORRECT to real 500mv or 50mv if (buttonValue>=1009 && buttonValue<=1020) //Switch the LED on if button is pressed // digitalWrite(ledPin, HIGH); button1 = 1; if (buttonValue>=999 && buttonValue<=1007) //button 1 press - кнопка 1 нажата и так далее - устанавливается нужная переменная. button2 = 1; // digitalWrite(ledPin, HIGH); if (buttonValue>=984 && buttonValue<=997) // digitalWrite(ledPin, HIGH); if (buttonValue>=953 && buttonValue<=982) // digitalWrite(ledPin, HIGH); if (buttonValue>=910 && buttonValue<=951) // digitalWrite(ledPin, HIGH); else button5=0; nobuttonpress=1; // digitalWrite(ledPin, LOW); //Switch the LED off if button is not pressed }
Хорошо, только резисторов точно таких не поставил, есть похожие. 56к вместо 100 и не с землей как в примере а с питанием, а маленькие резисторы на землю. Так ведь дисплей то работает – вот и вспомогательная программа- при нажатии кнопки число показывает, (заодно это вольтметр используя аналоговый пин). * можно не заморачиваться и вывести на последовательный порт в окошко на компе. Но не интересно.
1 2 3 4 5connect buttonsto analog pin resistor 56k to +5v resistors 2k 3k 1k to buttons display value to 6-digit Nixie tubes
програмка по считыванию ( и установке) времени – работа с микросхемой часов ds3231sn . поскольку она одна без модуля к ней резисторы pull up подтяжка на 5 вольт и микросхема памяти отдельно 24c32 . еще ставится батарейка литиевая – ну да от часов – на 10 лет работы. Цепь подзарядки есть на модуле – так ее не надо припаивать – и на модуле отсоединить отпаяв диод а то батарейка вздуется – она не рассчитана на 5 вольт подзарядку – эта цепь на 3 аккумулятора железо-никель, как на первой плате ibm pc 1980 -1986. На материнке компьютера более правильная схема – 2 диодика 1n4148 один плюсом к батарее а другой плюсом к 3 вольтовому питанию. минусы соединены вместе и на чип точного времени ( в материнке он всторен в южный мост.) В этих часах нет 3-вольтового питания но его можно сделать из 5 вольт добавив маленький линейный стабилизатор ams1117-3.3 – специально чтобы не расходовалась батарея часов при работе от 12 вольт или от сети, но мне кажется – уточнить – что внутри чипа уже есть эта схема – то есть он питается и от 5 вольт и есть вход от 3 – вольтовой батареи. (во вложениях заводское описание – datasheet.) в этом абзаце разбор схемы ibm pc как устроено питание часов и почему на некоторыз платах батарею менять раз в полгода а на других 10 лет не трогать и работает.
Декатрон раз в секунду рисует пружинку или маятник. Если штырьки вспыхивают чаще и все то они не отравливаются, молибден за разумный промежуток времени не испарится, сплав с вольфрамом тем более. При прожиге ламп источник спокойно выдавал 12 ватт, при работе будет 6 .. 9 все таки, сильно большие резисторы не буду ставить а то цифры будут тусклые.
делаю сразу часы в другое помещение. То же самое только ин8-2 или есть ин12б – в 2 раза меньше сборка при той же высоте цифр почти и нашел еще 2 декатрона. Не поленюсь переключать режим декатрона с основной ардуинки часов – надо 2 лапы – режим и время – если будут свободные выделить , если мало – то можно еще один 595-й регистр. Пятерка почти прожглась на лампе МЭЛЗ – она по-видимому ни разу не включалась за 50 лет, лампа работала в приборе а может в кассе или калькуляторе. Потребовалось 60 часов примерно в прыгающем режиме – программка сверху, перебор 00 -99 и обратно с чередованием 4 раза в секунду, плохо горящие пятерки семерки восьмерки девятки на 5 секунд все включаются и непрерывно, резистор 15к. Меняю пробившуюся ИД1 в десятках часов – вот так выглядит – поломка – светятся сразу все цифры в лампе, попало видно высокое как то на выход.
пайка микросхемы часов и 4 кнопок – пятая для подсветки она ни к чему (может только режим декатрона переключать)
Выбор часов на ИН-1 . Они большущие больше только чешские или ИН18 И светят довольно ярко – почти на солнце снимок.
нет запуска блока примерно 2 секунды после включения – запуск есть, заряжается кондер по высокому.
1 2 3 1 2 3
программа – блоки работы с ds3231 памятью 24с32 или похожей, кнопки – 3 с резисторами на аналоговый вход зато на один. Что то передается на другую ардуинку с декатроном – режим или быстро-мндленно. датчик освещения может прикручу. Индикация в статике – и светит конкретным оранжевым огнем, что то может с регулировкой света ночью – только не отключать. И так добивает этот свет в подьезде – чтобы его включить нало щелкнуть языком а то и гавкнуть. А часы должны показывать время, ворочаться шевелиться и щелкать ночью неохота. Ниже чуть алгоритм.
13 – летняя волчица не пугаться собачка она стесняется кусать и правильно . Красивая зверюга. С девушкой рядом на заднем плане, май 2020.
// это в общем то дисплей часов. Декатрон отдельно, на нем раз в секунду будет пружинка //или маятник. 6 ID1 6 IN1 3 hc595 #include #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 12 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 #define NUM_REGISTERS 3 //how many registers are in the chain //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte second = 86; byte minute = 79; byte hour = 78; void setup(){ pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); Serial.begin(9600); } void loop(){ // byte second, minute, hour; // shifter.setAll(HIGH); byte second = 77; byte minute = 77; byte hour = 77; //delay(5000); displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(5000); nixietrainer(); second = 66; minute = 66; hour = 66; shifter.clear(); shifter.write(); //send changes to the chain and display them delay(200); displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(5000); nixietrainer(); second = 55; minute = 55; hour = 55; shifter.clear(); shifter.write(); //send changes to the chain and display them delay(200); displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(5000); nixietrainer(); second = 88; minute = 88; hour = 88; shifter.clear(); shifter.write(); //send changes to the chain and display them delay(200); second = second >>2; minute= minute >>1; hour= hour >>3; displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(5000); //set all pins on the shift register chain to LOW // shifter.write(); //send changes to the chain and display them shifter.clear(); //delay(2000); shifter.write(); // shifter.setPin(0, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(1, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(2, LOW); shifter.setPin(3, LOW); // shifter.setPin(4, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(7, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, LOW); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(14, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(20, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(21, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(22, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.write(); shifter.clear(); delay(100); //} //void looptest(){ byte s1, s2, m1, m2, h1, h2; for (x = 0; x<100; x++){ // count from 0 to 99 // nixies = charTable[x]; // translate into a byte to send to the shift register second = x; minute= x-1; hour =x-2; s1=second % 10; s2=second / 10; m1=minute % 10; m2=minute / 10; h1=hour % 10; h2=hour / 10; //second = second +1; //minute = minute +1; //hour = hour +1; displayTime(second, minute, hour); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(200); // 99 ... 0 80 90 70 79 89 99 //hour= h2 || h1; //minute= m2 || m1; //second= s2 || s1; hour= 100 - hour; minute= 100 - minute; second= 100 - second; displayTime(hour, minute, second); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(200); } delay(300); shifter.clear(); shifter.write(); delay(100); nixietrainer(); shifter.setAll(HIGH); //set all pins on the shift register chain to LOW shifter.write(); //send changes to the chain and display them shifter.clear(); shifter.setPin(1, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(3, HIGH); shifter.setPin(5, HIGH); shifter.setPin(7, HIGH); shifter.setPin(9, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(11, HIGH); shifter.setPin(13, HIGH); shifter.setPin(15, HIGH); shifter.setPin(17, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.write(); //send changes to the chain and display them //notice how you only call write after you make all the changes you want to make delay(1700); shifter.setAll(HIGH); //Set all pins on the chain high shifter.write(); //send changes to the chain and display them delay(1500); } void loop2(){ nixies = 255; // create a blank byte updateShiftRegister(); // send the blank byte to the shift register delay(2500); for (x = 0; x<100; x++){ // count from 0 to 99 nixies = charTable[x]; // translate into a byte to send to the shift register updateShiftRegister(); //send to the shift register delay(500); Serial.print("x = "); Serial.println(x); Serial.print("nixies = "); Serial.println(nixies);} } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void displayTime(byte second, byte minute, byte hour) { //byte second, minute, hour; // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; prints(second); printm(minute); printh(hour); } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } /* void nixieinv (int n, int val) { // use 74141 or not - 10 hv transistors w/ other hex to 10 decimal decoder - inverted switch (val) { case 0: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 1: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 2: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 3: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 4: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 5: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 6: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 7: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 8: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 9: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 10: //off break; } } */ void nixietrainer() { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // подтверждаю что логика верная - если подать 11 22 33 то загорятся именно эти цифры - 3 регистра, 6 ид1 6 //ламп
все соединения проверены тестером Ц 20 цешкой – на режиме 1000 ом как проверять диодики и светодиоды. В тестере 2 элемента 18650 последовательно вместо 5 вольтовой батареи – это обольше но там есть переменник – крутилка установки нуля.
проба с новой платкой регистров и с часами (и с 24c32) пока не запаял батарейку. *используется библиотека Wire и DS3231 – не так как в примере выше считывание и запись напрямую по I2C.
#include <Wire.h> #include <ds3231.h> struct ts t; void setup() { Serial.begin(9600); Wire.begin(); DS3231_init(DS3231_CONTROL_INTCN); /*---------------------------------------------------------------------------- In order to synchronise your clock module, insert timetable values below ! ----------------------------------------------------------------------------*/ t.hour=12; t.min=30; t.sec=0; t.mday=25; t.mon=12; t.year=2019; DS3231_set(t); } void loop() { DS3231_get(&t); Serial.print("Date : "); Serial.print(t.mday); Serial.print("/"); Serial.print(t.mon); Serial.print("/"); Serial.print(t.year); Serial.print("\t Hour : "); Serial.print(t.hour); Serial.print(":"); Serial.print(t.min); Serial.print("."); Serial.println(t.sec); delay(1000); }
ру ус рус ованы функциистдезе ой и верд пв программе упрощенный выво и здесь ви вирус ап чхи комп .. Полечил.
код проекта взят с разных похожих но есть и что придумано по ходу . Вот довольно неплохая программа с множеством функций – для отладки заменил библиотеки в каталоге ардуино на те что в проекте и все собралось .https://github.com/isparkes/ArdunixNix6
#include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time
(Отличие что там динамическая индикация а здесь статика и эффекты например по другому надо делать)
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 12 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // Back light #define MODE_BACKLIGHT_MODE 23 // #define MODE_RED_CNL 24 // #define MODE_GRN_CNL 25 // #define MODE_BLU_CNL 26 // #define MODE_CYCLE_SPEED 27 // speed the colour cycle cyles at // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // ************************************************************ // LED brightness correction: The perceived brightness is not linear // ************************************************************ const byte dim_curve[] = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, }; const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 #define USE_LDR_DEFAULT true // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true #define NUM_REGISTERS 3 //how many registers are in the chain // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; byte useRTC = false; // true if we detect an RTC byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; void setup(){ // Read EEPROM values readEEPROMValues(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); setTime(12, 34, 56, 1, 3, 2017); // ! и оно работает 16 37 36 через 3 минуты getRTCTime(); pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); Serial.begin(9600); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running // impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } // performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); getRTCTime(); byte secondes = second(); byte minutes = minute(); byte hours = hour(); displayTime(secondes, minutes, hours); // display the real-time clock data on the Serial Monitor shifter.write(); secondes = 77; minutes = 77; hours = 77; delay(5000); nixietrainer(); shifter.clear(); shifter.write(); //send changes to the chain and display them delay(200); displayTime(secondes, minutes, hours); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(1000); secondes = 66; minutes = 66; hours = 66; displayTime(secondes, minutes, hours); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(5000); //set all pins on the shift register chain to LOW // shifter.write(); //send changes to the chain and display them shifter.clear(); //delay(2000); shifter.write(); // shifter.setPin(0, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(1, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(2, LOW); shifter.setPin(3, LOW); // shifter.setPin(4, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(7, LOW); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, LOW); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(14, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(20, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(21, HIGH); //set pin 1 in the chain(second pin) HIGH // shifter.setPin(22, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.write(); shifter.clear(); delay(100); //} //void looptest(){ byte s1, s2, m1, m2, h1, h2; for (x = 0; x<100; x++){ // count from 0 to 99 // nixies = charTable[x]; // translate into a byte to send to the shift register secondes = x; minutes= x-1; hours =x-2; s1=secondes % 10; s2=secondes / 10; m1=minutes % 10; m2=minutes / 10; h1=hours % 10; h1=hours / 10; //second = second +1; //minute = minute +1; //hour = hour +1; displayTime(secondes, minutes, hours); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(200); hours= h2 ^ h1; minutes= m2 ^ m1; secondes= s2 ^ s1; displayTime(hours, minutes, secondes); // display the real-time clock data on the Serial Monitor// not use 74141 shifter.write(); delay(200); } delay(300); shifter.clear(); shifter.write(); delay(100); //nixietrainer(); shifter.setAll(HIGH); //set all pins on the shift register chain to LOW shifter.write(); //send changes to the chain and display them shifter.clear(); shifter.setPin(1, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(3, HIGH); shifter.setPin(5, HIGH); shifter.setPin(7, HIGH); shifter.setPin(9, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(11, HIGH); shifter.setPin(13, HIGH); shifter.setPin(15, HIGH); shifter.setPin(17, HIGH); //set pin 1 in the chain(second pin) HIGH shifter.setPin(19, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.write(); //send changes to the chain and display them //notice how you only call write after you make all the changes you want to make delay(170); shifter.setAll(HIGH); //Set all pins on the chain high shifter.write(); //send changes to the chain and display them delay(1500); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) getRTCTime(); } } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void displayTime(byte secondes, byte minutes, byte hours) { //byte second, minute, hour; // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; prints(secondes); printm(minutes); printh(hours); } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void nixieinv (int n, int val) { // use 74141 or not - 10 hv transistors w/ other hex to 10 decimal decoder - inverted switch (val) { case 0: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 1: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 2: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 3: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 4: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 5: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 6: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 7: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 8: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 9: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 10: //off break; } } void nixietrainer() { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } // Return back to I2C in slave mode Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); Wire.endTransmission(); Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } dayBlanking = EEPROM.read(EE_DAY_BLANKING); if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // .. упрощенная но работающая функция установка времени 2017 и вывод на дисплей каждый цикл - тест остается
убрал проверки и устройство превратилось в часы . Минимальная программа показывающая только время. На 6 лампах час минуты секунды. И раз в минуту перебор всех цифр примерно 2 секунды.
В основном цикле запоминаются миллисекунды от начального момента – после сброса счетчика, считается количество циклов за секунду и если секунда прошла выполняется подпрограмма. Раз в секунду считывается время из часовой микросхемы записывается в регистры и выводится на дисплей то есть на лампы. Это детальное описание программы например как техзадание на программное обеспечение изделия .. если прошла минута то вызывается подпрограмма очистки ламп от отравления – nixietrainer . Количество циклов в секунду никуда не выводится – это можно для отладки вывести в последовательный порт.
# просто вывод времени на дисплей - это часы #include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 12 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // Back light #define MODE_BACKLIGHT_MODE 23 // #define MODE_RED_CNL 24 // #define MODE_GRN_CNL 25 // #define MODE_BLU_CNL 26 // #define MODE_CYCLE_SPEED 27 // speed the colour cycle cyles at // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // ************************************************************ // LED brightness correction: The perceived brightness is not linear // ************************************************************ const byte dim_curve[] = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, }; const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 #define USE_LDR_DEFAULT true // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true #define NUM_REGISTERS 3 //how many registers are in the chain // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = false; // true if we detect an RTC byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi int impressionsPerSec = 0; //loop int lastImpressionsPerSec = 0; // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; void setup(){ // Read EEPROM values readEEPROMValues(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); setTime(12, 34, 56, 17, 5, 2021); // ! и оно работает 16 37 36 через 3 минуты getRTCTime(); pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); Serial.begin(9600); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; delay(50); } //main loop // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // feed the watchdog wdt_reset(); getRTCTime(); byte secondes = second(); byte minutes = minute(); byte hours = hour(); displayTime(secondes, minutes, hours); // display the real-time clock data on the Serial Monitor shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) getRTCTime(); } nixietrainer(); shifter.clear(); shifter.write(); //send changes to the chain and display them } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void displayTime(byte secondes, byte minutes, byte hours) { //byte second, minute, hour; // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; prints(secondes); printm(minutes); printh(hours); } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void nixieinv (int n, int val) { // use 74141 or not - 10 hv transistors w/ other hex to 10 decimal decoder - inverted switch (val) { case 0: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 1: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 2: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 3: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; case 4: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 5: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 6: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 7: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 8: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 9: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 10: //off break; } } void nixietrainer() { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } // Return back to I2C in slave mode Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); Wire.endTransmission(); Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } dayBlanking = EEPROM.read(EE_DAY_BLANKING); if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; }
этот код работал с внутренним таймером Ардуино.
А теперь – чипы точного времени и памяти 24c32 припаяны . Ставим значение useRTC в true . в коде комментарии есть.
и — время запоминается в чипе DS3231 и при перезагрузке программы скетча (до выключения платы) не теряется.
еще опять можно запускать без юсби кабеля если поставить debug=false;
раскомментировать строку _un-comment line_ // setRTC(); заменить на setRTC(); и проверка чипа точного времени выполнена. * один раз скомпилировать – запустить – закомментировать обратно – скомпилировать загрузив второй раз в ардуино. Строка должна быть в одном месте. Теперь часы идут не зависимо от загрузки программы или сброса ардуинки. Время считывается из чипа следующей строкой getRTCTime;
.. useRTC=true; .. void setup(){ // Read EEPROM values readEEPROMValues(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again setTime(6, 34, 56, 17, 5, 2021); // ! и оно работает 16 37 36 через 3 минуты // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip // setRTC(); getRTCTime(); pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 } void loop(){
Дальше добавляю функции. Установку времени кнопками (или с вайфай) , вывод на дисплей температуры и день месяц год – все есть в данных с часовой микросхемы Maxim DS3231.
#include <DS3231.h> // Northern Widget LLC, et al 1.0.2, via IDE, public domain #include <extEEPROM.h> // Jack Christensen, 3.4.1, via IDE licensed under CC BY-SA 4.0. #include <EwmaT.h> // 1.0.2 via IDE, jonnieZG, https://github.com/jonnieZG/EWMA, MIT license #include <ezTime.h> // 0.8.3 Rop Gonggrijp, via IDE //#define RTCtestNtpSet 2 // deliberately sets RTC wrong for testing. 1=slow 997 ms, 2=fast 997 ms // forward declarations void debugMsg(String msg, int level=1); void debugMsgln(String msg, int level=1); void tryWLAN(); void ctlLog(); void stopLogDaily(); signed char getAgingTrim(); void oncePerFive(); void oncePerHour(); // end forward declarations String getNtpTZ(); String getNtpServer(); unsigned short int getNtpPoll(); #define RTC_EEPROM_SIZE 4096 #define RTC_EEPROM_SIG "mjs!" /* * EEPROM on DS3231 module * 0 (1) Last set aging trim (so we have it if battery goes away) * 1-2 (2) Year * 3 (1) Month * 4 (1) Day * 5 (1) Hour * 6 (1) Minute * 7 (1) Second * 8-11 (4) Last time set (Unix time) * * 4092-4095 (4) Valid signature (RTC_EEPROM_SIG) */ #define RtcEepromAge 0 #define RtcEepromYear 1 #define RtcEepromMonth 3 #define RtcEepromDay 4 #define RtcEepromHour 5 #define RtcEepromMinute 6 #define RtcEepromSecond 7 #define RtcEepromLastSetTime 8 #define RTC_DRIFT_FACTOR 1.0 // multiply drift trim correction by this #define NTP_DEFAULT_TZ "EST+5EDT,M3.2.0,M11.1.0" // full POSIX format #define NTP_DEFAULT_INTERVAL 7207 // seconds, best if not a multiple of 60 #define NTP_DEFAULT_SERVER "0.pool.ntp.org" #define NTP_MIN_INTERVAL 601 // seconds #define NTP_MAX_INTERVAL 65535 // ~18 hours DS3231 Clock; extEEPROM rtc_eeprom(kbits_32, 1, 32, 0x57); #define RTC_I2C_ADDR 0x68 #define RTC_EEPROM_I2C_ADDR 0x57 // ZS-042/HW-84 modules have pullups on A0-A2 #define RTC_DEFAULT_TRIM 0 // aging trim for ds3231, higher is slower // ~0.1 ppm per (~9 ms/day, 0.26 sec/month), higher is slower, // 11.6 ppm is ~ 1 sec/day #define RTC_MAX_UNSYNC 125 // adjust when we're this many ms out of sync with NTP, for 601 sec NTP polls #define SQW_PIN 14 // GPIO 14 (D5) on both, SQW from DS3231 bool rtcPresent = false; bool rtcNeedsTime = false; timeStatus_t ntp_state; // timeNotSet, timeSet, timeNeedsSync bool twentyFourHourClock = true; bool Century=false; bool h12; bool PM; int Year = 2019; byte Month = 4, Day = 1, Weekday = 1, Hour = 0, Minute = 0, Second = 0; // April fool's volatile long int rtc_ms = 0; // below underflows with negatives, so all uses add 1000000. EwmaT <long int> rtc_diff_ewmat(2, 10, 1000000); // 2/10:weight for new additions, 1000000:starting value long int rtc_diff_filtered = 0; // filtered value int rtc_IRQ = false; // faster to set an int than a bool? unsigned long int rtc_secs; String ntpServer = NTP_DEFAULT_SERVER; unsigned short int ntpInterval = NTP_MAX_INTERVAL; String ntpTZ = NTP_DEFAULT_TZ; //posix string String tzName; // used for lookup String tzPosix; // used for lookup Timezone myTZ; unsigned int rtc_max_unsync = RTC_MAX_UNSYNC * sqrt(ntpInterval/600); // can get more out of sync with longer ntp updates String ntp_state_string(timeStatus_t state) { if ( state == timeSet ) return F("NTP time set"); if ( state == timeNotSet ) return F("NTP time not set"); if ( state == timeNeedsSync ) return F("NTP time needs sync"); return F("err"); } void setupRtcSQW() { pinMode(SQW_PIN, INPUT); // From DS3231 square wave output 1 Hz - 8.192 KHz digitalWrite(SQW_PIN, HIGH); // internal pullup } // ************************************************************ // Read/write the eeprom on the RTC module // ************************************************************ byte read_rtc_eeprom(int address) { // Read a byte at address in EEPROM memory. byte data[1]; byte i2cStat = rtc_eeprom.read(address, data, 1); debugMsg(F("Reading RTC eeprom, "),5); debugMsgln(String(address)+": "+String(data[0]),5); return data[0]; } void write_rtc_eeprom(int address, byte data) { debugMsg(F("Writing RTC eeprom, "),4); debugMsgln(String(address)+": "+String(data),4); byte writebyte[1]; writebyte[0] = data; byte i2cStat = rtc_eeprom.write(address, writebyte, 1); // Write cycle time (tWR). See EEPROM memory datasheet for more details. delay(10); } void setRtcLastSetTime(time_t set_time) { if (!rtcPresent) return; debugMsgln(F("setRtcLastSetTime"),2); time_t unow = set_time; write_rtc_eeprom(RtcEepromYear, Year>>8); write_rtc_eeprom(RtcEepromYear+1, Year%256); write_rtc_eeprom(RtcEepromMonth, Month); write_rtc_eeprom(RtcEepromDay, Day); write_rtc_eeprom(RtcEepromHour, Hour); write_rtc_eeprom(RtcEepromMinute, Minute); write_rtc_eeprom(RtcEepromSecond, Second); for (int i=0 ; i<4 ; i++) { write_rtc_eeprom(RtcEepromLastSetTime+i, unow%256); unow = unow >> 8; } } time_t getRtcLastSetTime() { if (!rtcPresent) return 0; time_t utime = 0; for (int i=3; i>-1; i--) { // read high byte first so we can bit shift utime = utime << 8; utime += read_rtc_eeprom(RtcEepromLastSetTime+i); } return utime; } time_t getUnixTime() { time_t unow; if (rtcPresent){ RTClib RTC; DateTime now = RTC.now(); unow = now.unixtime(); } else { unow = UTC.now(); // from ntp } return unow; } void writeRtcEepromSig() { String chkstr = F(RTC_EEPROM_SIG); for (int i = 0; i < 4 ; i++) { write_rtc_eeprom(i + RTC_EEPROM_SIZE -4, chkstr[i]); } debugMsgln("Wrote RTC eeprom sig: " + chkstr,3); } // ************************************************************ // Get the time from the RTC // ************************************************************ void getRtcTime() { if (rtcPresent) { Year = Clock.getYear() + 2000; Month = Clock.getMonth(Century); Day = Clock.getDate(); Weekday = Clock.getDoW(); Hour = Clock.getHour(twentyFourHourClock, PM); Minute = Clock.getMinute(); Second = Clock.getSecond(); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } } String getRtcTimeString(int full = 1) { // form: 1=full, 0=HMS if (rtcPresent) { String RTCTime = ""; getRtcTime(); if (full) { RTCTime = String(Month)+"/"+String(Day, DEC)+"/"+String(Year, DEC)+" "; } RTCTime += String(Hour, DEC)+": "+String(Minute, DEC)+": "+String(Second, DEC); return RTCTime; } } // ************************************************************ // Set the date/time in the RTC // ************************************************************ void setRtc(boolean writeee=false) { Clock.setClockMode(false); // false = 24h Clock.setYear(Year % 100); Clock.setMonth(Month); Clock.setDate(Day); Clock.setDoW(Weekday); Clock.setHour(Hour); Clock.setMinute(Minute); Clock.setSecond(Second); // The OSF is cleared by function setSecond();. signed char age = getAgingTrim(); rtc_diff_ewmat.reset(); //reset averaging filter rtc_diff_filtered = 0; if (writeee) { write_rtc_eeprom(RtcEepromYear, Year>>8); write_rtc_eeprom(RtcEepromYear+1, Year%256); write_rtc_eeprom(RtcEepromMonth, Month); write_rtc_eeprom(RtcEepromDay, Day); write_rtc_eeprom(RtcEepromHour, Hour); write_rtc_eeprom(RtcEepromMinute, Minute); write_rtc_eeprom(RtcEepromSecond, Second); write_rtc_eeprom(RtcEepromAge, age); setRtcLastSetTime(UTC.now()); writeRtcEepromSig(); } } bool setRtcTimeNTP() { if (!WiFi.isConnected()) return false; // not unless connected updateNTP(); waitForSync(3); if (timeStatus() == timeSet) { debugMsgln(F("Setting RTC from NTP"),1); #if RTCtestNtpSet == 1 // set 997 ms slow while ( ms() != 997) yield(); // for testing, deliberately set rtc wrong #elif RTCtestNtpSet == 2 // set 997 ms fast while ( ms() != 3) yield(); // for testing, deliberately set rtc wrong Clock.setSecond(UTC.second()+1); // for testing, note: may wrap with minutes #else while ( ms() < 6 ) yield(); // this waits for a seconds rollover while ( ms() > 5 ) yield(); // then updates the RTC as fast as possible Clock.setSecond(UTC.second()); #endif Clock.setMinute(UTC.minute()); Clock.setHour(UTC.hour()); Clock.setDoW(UTC.weekday()); Clock.setDate(UTC.day()); Clock.setMonth(UTC.month()); Clock.setYear(UTC.year() % 100); setRtcLastSetTime(UTC.now()); rtc_diff_ewmat.reset(); //reset averaging filter rtc_diff_filtered = 0; return true; } else { return false; } } bool setRtcTime(String rtcTime) { debugMsg(F("setRtcTime to "),1); debugMsgln(rtcTime,1); Year = rtcTime.substring(0,4).toInt(); Month = rtcTime.substring(4,6).toInt(); Day = rtcTime.substring(6,8).toInt(); Weekday = rtcTime.substring(8,9).toInt(); Hour = rtcTime.substring(9,11).toInt(); Minute = rtcTime.substring(11,13).toInt(); Second = rtcTime.substring(13).toInt(); setRtc(true); } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRtcTemp() { if (rtcPresent) { return Clock.getTemperature(); } else { return 0.0; } } signed char getAgingTrim() { signed char age = 0; Wire.beginTransmission(RTC_I2C_ADDR); Wire.write(0x10); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDR,1); while (Wire.available()) { age = Wire.read(); } return age; } void setAgingTrim(signed char age) // ~0.1 ppm per, higher is slower 11.6 ppm is ~ 1 sec/day { Wire.beginTransmission(RTC_I2C_ADDR); Wire.write(0x10); Wire.write(age); Wire.endTransmission(); write_rtc_eeprom(RtcEepromAge, age); rtc_diff_ewmat.reset(); //reset averaging filter rtc_diff_filtered = 0; /* * New values, including changes to the AGE register, are loaded only when a change in the temperature * value occurs, or when a user-initiated temperature conversion is completed. */ getRtcTemp(); } void resetRtcEeprom() { setRtcTimeNTP(); setRtcLastSetTime(UTC.now()); setAgingTrim(RTC_DEFAULT_TRIM); writeRtcEepromSig(); } String checkRtcEeprom() { /* * Check if valid, reset if not */ debugMsg(F("RTC EEPROM check..."),1); String chkstr1 = ""; String chkstr2 = "x"; // to enter while() int tries = 0; while ( (chkstr1 != chkstr2) && tries <3 ) { chkstr1 = ""; chkstr2 = ""; for (int cnt = RTC_EEPROM_SIZE - 4; cnt < RTC_EEPROM_SIZE; cnt++) { chkstr1 += char(read_rtc_eeprom(cnt)); chkstr2 += char(read_rtc_eeprom(cnt)); } tries++; } if (chkstr1 != F(RTC_EEPROM_SIG)) { debugMsgln(F("invalid, resetting"),1); debugMsgln("1: "+chkstr1+", 2: "+chkstr2,1); resetRtcEeprom(); } else { debugMsg(chkstr1+"...",3); debugMsgln(F("valid"),1); } return chkstr1; } float getRtcppm() { float howlong; howlong = UTC.now() - getRtcLastSetTime(); // number of seconds since we last set RTC time return -(rtc_diff_ewmat.output()-1000000.0) * 1000.0 / howlong; // drift in ppm } void checkClocks(int32_t rtc_diff_filtered) { debugMsgln(F("checkClocks"),3); if (rtcPresent && !rtcNeedsTime && (WiFi.getStatusBits() & (STA_HAS_IP_BIT | STA_HAS_IP6_BIT)) ) { if (timeStatus() != timeSet) { // ntp went away // TODO retry NTP debugMsgln(F("Setting time from RTC"),3); UTC.setTime(getUnixTime()); // from RTC to eztime } else { uint32_t howlong; float drift; int new_trim; if (abs(rtc_diff_filtered) >= rtc_max_unsync) { // only adjust if we're off by so much debugMsgln(F("RTC/NTP out of sync"),3); if ((now() - lastNtpUpdateTime() > 120) ) { // first make sure local drift isn't the issue debugMsgln(F("Poll NTP"),3); updateNTP(); return; // we'll be back in a minute if it's still off } howlong = UTC.now() - getRtcLastSetTime(); // number of seconds since we last set RTC time drift = -rtc_diff_filtered * 10000.0 / howlong; // drift in 0.1 ppm, close to the DS3231 offset precision, - means RTC is slow new_trim = getAgingTrim() + (drift * RTC_DRIFT_FACTOR); debugMsg(F("howlong: "),4); debugMsgln(String(howlong),4); debugMsg(F("rtc_diff_filtered: Got model preference"),4); debugMsgln(String(rtc_diff_filtered),4); debugMsgln(F(" ppm"),4); if (new_trim != getAgingTrim()) { if (new_trim < -127) new_trim = -127; if (new_trim > 127) new_trim = 127; if (abs(new_trim) != 127) { // if we're at the extreme, probably an error, skip debugMsg(F("Changing RTC trim, drift: "),1); debugMsg(String(rtc_diff_filtered),1); debugMsg(F(" ms, ppm: "),1); debugMsg(String(drift/10.0,3),1); debugMsg(", old trim: " + String(getAgingTrim()),1); debugMsgln(", new trim: " + String(new_trim),1); setAgingTrim(new_trim); } } else { debugMsgln("RTC drift of " + String(drift/10.0,3) + "ppm within limit",2); } setRtcTimeNTP(); //resync } } } } /* * IRQ, RTC marks millis() every second */ static void IRAM_ATTR rtcIRQ() { // handles interrupts from RTC, can't do much here rtc_ms = millis(); // tracks difference between ntp and rtc rtc_IRQ = true; if (--myWDT <= 1) ESP.restart(); // loop watchdog ; } /* * Time diff processing happens once per minute, using a timestamp of a 1/sec * RTC interrupt. * * The result is real_rtc_diff_ms, which is where an RTC second is positioned * against an ntp second. A negative value indicates it occured before the * ntp second. * * We start by collecting timestamps from NTP and RTC. If an RTC interrupt * occurs while getting time from it, it's invalid so we try again. That should * always work, because the next IRQ shouldn't be until a second later. * * rtc_ms is when the RTC sent an interrupt at the start of its last second, * in millis(). If oncePerMinute gets delayed before running, that will be * reflected in opm_ms. So, we subtract that from current millis() to adjust. * So, the last rtc second happened at: * * ms_diff = -(opm_millis - opm_ms - rtc_ms); * * If ms_diff is decreasing, RTC is running faster than NTP (getting more ahead). * If exactly sync'd rtc_secs = opm_secs and ms_diff = 0. * * Then, we have to look at whole seconds. If opm_secs>rtc_secs, the rtc has gotten * behind (late) by more a second, so include that. * * real_rtc_diff_ms = ((opm_secs-rtc_secs) * 1000) + ms_diff; * * Note that the local time can change by ms per minute, because * it depends on the ESP crystal/resonator, which may not be particularly * accurate. So, the difference may rarely converge exactly. So, we allow a * few ms difference when adjusting. * */ void oncePerMinute() { // not necessarily _on_ the minute int32_t ms_diff; int32_t real_rtc_diff_ms; deleteEvent(oncePerMinute); setEvent(oncePerMinute,now()+60); // for next time debugMsgln(F("oncePerMinute"),3); if ( (timeStatus() == timeSet) && rtcPresent && !rtcNeedsTime ) { // ntp and rtc running uint32_t opm_millis = millis(); // grab some times immediately uint16_t opm_ms = UTC.ms(); uint32_t opm_secs = UTC.now(); rtc_IRQ = false; // watch for IRQ while getting time uint32_t opm_rtc_ms = rtc_ms; rtc_secs = getUnixTime(); // what second does rtc think it is? if (rtc_IRQ) { // got an IRQ, timestamps may be wrong, try again debugMsgln(F("RTC IRQ while processing, try again"),4); opm_millis = millis(); opm_ms = UTC.ms(); opm_secs = UTC.now(); rtc_IRQ = false; opm_rtc_ms = rtc_ms; rtc_secs = getUnixTime(); if (rtc_IRQ) { // didn't expect that, we just got one... debugMsgln(F("Second RTC IRQ while processing time, aborting"),1); return; } } ms_diff = -(opm_millis - opm_ms - opm_rtc_ms); debugMsgln("opm_millis: "+String(opm_millis),5); debugMsgln("opm_ms: "+String(opm_ms),5); debugMsgln("opm_rtc_ms: "+String(opm_rtc_ms),5); debugMsgln("ms_diff: "+String(ms_diff),5); if (ms_diff < -999 || ms_diff > 999) { // sanity check, debugMsg(F("ms_diff out of bounds: "),2); debugMsgln(String(ms_diff),3); return; } real_rtc_diff_ms = ((opm_secs-rtc_secs) * 1000) + ms_diff; debugMsgln("rtc_secs: "+String(rtc_secs),5); debugMsgln("opm_secs: "+String(opm_secs),5); debugMsgln("ms_diff: "+String(ms_diff),5); debugMsgln("real_rtc_diff_ms: "+String(real_rtc_diff_ms),5); // moving average-like filter, 1000000 (1000 second) offset because it underflows on negative numbers rtc_diff_filtered = rtc_diff_ewmat.filter(real_rtc_diff_ms+1000000)-1000000; debugMsgln("RTC diff real/filt: " + String(real_rtc_diff_ms) + "/" + String(rtc_diff_filtered),4); if (timeStatus() == timeSet && abs(real_rtc_diff_ms - rtc_diff_filtered) < 5 ) { // only if NTP is running and checkClocks(rtc_diff_filtered); // we've averaged to within 5 ms } } // other oncePerMinute processing goes here ctlLog(); // log controller data } void oncePerFive() { // every 5 minutes deleteEvent(oncePerFive); UTC.setEvent(oncePerFive,UTC.now()+300); debugMsgln(F("oncePerFive"),3); tryWLAN(); // try to connect as station if (logFile) logFile.flush(); // flush logs every 5 minutes if (ctl_logFile) ctl_logFile.flush(); #ifdef EZT_DEBUG if (ezt_logFile) ezt_logFile.flush(); #endif } void oncePerHour() { // not necessarily _on_ the hour deleteEvent(oncePerHour); UTC.setEvent(oncePerHour,UTC.now()+3600); debugMsgln(F("oncePerHour"),3); if ((timeStatus() == timeNeedsSync) && rtcPresent) UTC.setTime(getUnixTime()); // lost ntp sync, update from RTC timeval epoch = {UTC.now(), UTC.ms()}; // FAT is not TZ aware, use local TZ settimeofday((const timeval*)&epoch, 0); // set ESP ToD, for SD file timestamps debugMsgln(F("settimeofday"),4); if (myTZ.hour() % 6 == 0 && !noController) { // every 6 hours debugMsgln("Modbus errors/tries: " + String(mbuserrs) + "/" + String(mbustries) + " (" + String(((double)mbuserrs/(double)mbustries)*100.,3) + "%)", 1); } // TODO logrotate? } void midnight() { deleteEvent(midnight); myTZ.setEvent(midnight,myTZ.now()+86400); debugMsgln("Midnight",1); stopLogDaily(); // save todays info } void eventConfirm() { debugMsgln(F("Events are running"),1); } void setupClocks() { unsigned short int ntp_temp; bool rtcNeedsTrim = false; // first, check for RTC if (!Wire.requestFrom(RTC_I2C_ADDR, 2)) { debugMsg(F("No "),1); } else { rtcPresent = true; } debugMsgln(F("RTC found"),1); if (rtcPresent) { // found RTC byte i2cStat = rtc_eeprom.begin(rtc_eeprom.twiClock100kHz); // check RTC EEPROM if ( i2cStat != 0 ) { debugMsgln(F("I2C Problem with RTC eeprom"),1); } delay(10); if (!Clock.oscillatorCheck()) { // check for Oscillator Stopped Flag (!good RTC) debugMsgln(F("RTC OSC stopped"),1); rtcNeedsTrim = true; // probably need to reload offset and set time, too rtcNeedsTime = true; setRtc(false); // set dummy time, clear OSF } } if (rtcPresent) { //previous check might have failed, found RTC, and it passed checks checkRtcEeprom(); if (rtcNeedsTrim) setAgingTrim(getAgingTrim()); debugMsgln(F("RTC configuring interrupts"),1); Clock.enableOscillator(true, false, 0); // Ena SQW output, but not on batt, 1 Hz attachInterrupt(digitalPinToInterrupt(SQW_PIN), rtcIRQ, FALLING); // runs rtcIRQ once a second, falling edge (start of second) } // using rtc // now, setup NTP myTZ.setDefault(); // setup NTP service tzPosix = getNtpTZ(); debugMsg(F("Setting NtpTZ to: "),1); debugMsgln(tzPosix,1); ntpTZ = tzPosix; myTZ.setPosix(tzPosix); ntpServer = getNtpServer(); debugMsg(F("Setting NtpServer to: "),1); debugMsgln(ntpServer,1); setServer(ntpServer); tzPosix = ""; // we were just using it temporarily ntp_temp = getNtpPoll(); debugMsg(F("Setting NtpPoll to: "),1); debugMsgln(String(ntp_temp),1); setInterval(ntp_temp); ntpInterval = ntp_temp; rtc_max_unsync = RTC_MAX_UNSYNC * sqrt(ntpInterval/600); delay(100); debugMsgln(F("NTP trying to sync..."),1); waitForSync(15); ntp_state = timeStatus(); if (ntp_state == timeSet) { debugMsg(F("NTP time is "),1); debugMsgln(myTZ.dateTime(RFC850),1); timeval epoch = {UTC.now(), UTC.ms()}; // FAT is not TZ aware, use local TZ settimeofday((const timeval*)&epoch, 0); // set ESP ToD, for SD file timestamps if (rtcNeedsTime) rtcNeedsTime = setRtcTimeNTP(); } else { debugMsgln(F("NTP not sync'd"),1); const char* remote_host = ntpServer.c_str(); /* if(Ping.ping(remote_host)) { debugMsg("Can ping ",1); } else { debugMsg("Can't ping ",1); } debugMsgln(ntpServer,1); */ if (rtcPresent && !rtcNeedsTime ) { debugMsgln(F("Setting time from RTC"),1); UTC.setTime(getUnixTime()); // from RTC to eztime debugMsg(F("RTC time is "),1); debugMsgln(myTZ.dateTime(RFC850),1); } ntp_state = timeStatus(); // tell NTP to keep trying } bootTime = UTC.now(); // record when we booted, setupClocks only called once during setup() } time_t getMidnight() { // returns time of local midnight in UTC tmElements_t tm ; breakTime(myTZ.now(), tm); tm.Hour = 0; tm.Minute = 0; tm.Second = 0; // beginning of today time_t midnight = makeTime(tm) + (myTZ.getOffset() * 60) + 86400; debugMsgln("midnight is "+String(midnight),3); return(midnight); } void setEvents() { // set timed events even if not ntp sync'd debugMsgln(F("Creating timed events"),1); deleteEvent(oncePerMinute); deleteEvent(oncePerFive); deleteEvent(oncePerHour); deleteEvent(eventConfirm); deleteEvent(midnight); UTC.setEvent(oncePerMinute,( UTC.now()-UTC.now()%60 ) +60 ); // top of minute (0 second) UTC.setEvent(oncePerFive,UTC.now()+20); UTC.setEvent(oncePerHour,UTC.now()+10); UTC.setEvent(eventConfirm,UTC.now()+5); UTC.setEvent(midnight, getMidnight()); } void checkNtp() { // watches for changes to ntp state if ( ntp_state != timeStatus() ) { //state changed ntp_state = timeStatus(); debugMsg(F("NTP state changed, "),1); debugMsgln(ntp_state_string(ntp_state),1); if ( (ntp_state == timeSet) && rtcNeedsTime ) { setRtcTimeNTP(); setEvents(); } } }
отладка программы Часы и температуру с микросхемы часов показывает . Надо добавить диоды на батарейное питание чтобы при работе от сети не садилась батарейка. Выяснилось что нужно 2 напряжения питания – включаю через диодики как на материнской плате и ставлю батарейку. Еще выяснилось что через часов 5 7 работы зависает – перепаял соединения, подключил к сбросу резистор на 100 килоом к питанию . Проверяю почти сутки работает . Да еще отладка – не так часто обращения к часовой микросхеме – из секундного цикла сразу убрал, оставил в минутном, может перенесу в третий – раз в час. * по логике лучше раз в минуту оставить. ! а оказалось что .. 5 вольт питания не доходило до микросхемы часов и регистра первого 74hc595.. фольга на плате надорвалась. у них ток потребления мизерный и так работало – за счет сигнала с ардуинки. Электроника наука о контактах.
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // Back light #define MODE_BACKLIGHT_MODE 23 // #define MODE_RED_CNL 24 // #define MODE_GRN_CNL 25 // #define MODE_BLU_CNL 26 // #define MODE_CYCLE_SPEED 27 // speed the colour cycle cyles at // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // ************************************************************ // LED brightness correction: The perceived brightness is not linear // ************************************************************ const byte dim_curve[] = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, }; const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 #define USE_LDR_DEFAULT true // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = true; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); if (Serial.available())Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(12, 56, 47, 3, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера //setRTC(); // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } /* 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds32321 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } testDS3231TempSensor1(); // fahrenheit celsius from ds3232 lib // float c = RTC.temperature() / 4.; //float f = c * 9. / 5. + 32.; // setRTCDateTime1(5, 34, 56, 29, 5, 21, 5); //read - write ds3231 2-nd time //timeDS3231(); nowMillis = millis(); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; delay(50); } //main loop void timeDS3231 () { byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; // retrieve data from DS3231 readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // if (hour == 23){hour=-1;} // if (minute == 59){minute=-1;} setDS3231time(second, minute, hour, dayOfWeek, dayOfMonth, month, year); if (debug) { Serial.print(F("DS3231_rd0=")); Serial.print(hour); Serial.print(":"); Serial.print(minute); Serial.print(":"); Serial.print(second); Serial.print("-day-"); Serial.print(dayOfWeek); Serial.print("-"); Serial.print(dayOfMonth); Serial.print("-"); Serial.print(month); Serial.print("-"); Serial.print(year+2000); Serial.println(); } } void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) { // sets time and date data to DS3231 Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set next input to start at the seconds register Wire.write(decToBcd1(second)); // set seconds Wire.write(decToBcd1(minute)); // set minutes Wire.write(decToBcd1(hour)); // set hours Wire.write(decToBcd1(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday) Wire.write(decToBcd1(dayOfMonth)); // set date (1 to 31) Wire.write(decToBcd1(month)); // set month Wire.write(decToBcd1(year)); // set year (0 to 99) Wire.endTransmission(); } void readDS3231time(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); // set DS3231 register pointer to 00h // routine works if battery inserted Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes of data from DS3231 starting from register 00h *second = bcdToDec1(Wire.read() & 0x7f); *minute = bcdToDec1(Wire.read()); *hour = bcdToDec1(Wire.read() & 0x3f); *dayOfWeek = bcdToDec1(Wire.read()); *dayOfMonth = bcdToDec1(Wire.read()); *month = bcdToDec1(Wire.read()); *year = bcdToDec1(Wire.read()); } // Convert decimal numbers to binary coded decimal byte decToBcd1(byte val) { return ( (val / 10 * 16) + (val % 10) ); } // Convert binary coded decimal to normal decimal numbers byte bcdToDec1(byte val) { return ( (val / 16 * 10) + (val % 16) ); } /* void rtctest1() { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //doTest(); testDS3231TempSensor(); //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! getRTCTime(); byte prevSeconds = secondes; unsigned long RTC_ReadingStartTime = millis(); // RTC_present = true; while (prevSeconds == secondes) { getRTCTime(); //Serial.println(RTC_seconds); if ((millis() - RTC_ReadingStartTime) > 3000) { Serial.println(F("Warning! RTC DON'T RESPOND!")); // RTC_present = false; break; } } // setTime(hours, minutes, secondes, day, month, year); } */ void testDS3231TempSensor1() { int8_t DS3231InternalTemperature=0; Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); Serial.print(F("DS3231_T_1-st-byte=")); Serial.println(DS3231InternalTemperature); if ((DS3231InternalTemperature<2) || (DS3231InternalTemperature>95)) { Serial.println(F("wrong C degrees DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } void setRTCDateTime1 (byte h, byte m, byte s, byte d, byte mon, byte y, byte w) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Wire.write(decToBcd1(s)); Wire.write(decToBcd1(m)); Wire.write(decToBcd1(h)); Wire.write(decToBcd1(w)); Wire.write(decToBcd1(d)); Wire.write(decToBcd1(mon)); Wire.write(decToBcd1(y)); // Wire.write(zero); //start Wire.endTransmission(); } /* void getRTCTime1() { Wire.beginTransmission(DS1307_ADDRESS); Wire.write(zero); Wire.endTransmission(); Wire.requestFrom(DS1307_ADDRESS, 7); secondes = bcdToDec(Wire.read()); minutes = bcdToDec(Wire.read()); hours = bcdToDec(Wire.read() & 0b111111); //24 hour time byte day_of_week = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday day = bcdToDec(Wire.read()); month = bcdToDec(Wire.read()); byte RTC_year = bcdToDec(Wire.read()); } */ // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика byte secondes = second(); byte minutes = minute(); //byte hours = hour() -4 ; display_nixietubes(secondes, minutes, hour()); // display the real-time clock data on the Nixies set data shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) if (useRTC) getRTCTime(); } digitalClockDisplay() ; //serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.clear(); shifter.write(); //send changes to the chain and display them } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes(byte secondes, byte minutes, byte hours) { //set data for display - 6 Nixie tubes with driver K155ID1 //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; prints(secondes); printm(minutes); printh(hours); } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; }
и ссылка на видео – светодиодная линейка. Расшифровка – первые 3 светодиода это лапки D8 D9 D11 и запись в 3 регистра используя библиотеку Shifter. А 5 и 6 – сигналы шины TwoWire то есть SDA SCL там чуть ниже уровень примерно 3 – вольтовый и светодиоды засвечиваются рубиновым а раз в минуту идет быстрый обмен – чтение чипа часов, энергонезависимая память распаяна но пока не используется. Библиотека часов обновлена из менеджера библиотек – вытаскиваю ее сюда а то на гугле она не совсем такая – возможно под другую версию или плату сделана. Ардуинка она десяток на Али на червонец но самая настоящая Адафрут и даже чип не поддельный. Светодиодная линейка на видео вообще антикварная она стояла в супер эвм ibm360 она же серия ЕС. Это было что то – компьютерный зал .. комната в 200 метров кв. Кабели коаксиал в миллиметра полтора. 190 если не вру 400 мегагерц. для сравнения ibm pc тогда работала на 8 мегагерц. Эмиттерно связаная логика – с огромной скоростью работы – Тетрис на зеленом мониторе на котором только буквы и цифры, девушка игривая не одетая совсем – картина из принтера мелкими значками @ собачка и $ денежный символ. в 1992 году все это хозяйство разобрали на золото и увезли в какой то кооператив за 500 денежных символов, да еще поддельных как оказалось..
схема светодиодной линейки . Не превышать ток 20 миллиампер а лучше 10 чтобы Ардуина не перегревалась. То есть резистор 500 ом ну 300 самый минимум. (2.8 вольт либо 1.6 падение на светодиоде либо 1.3 на инфракрасном)
а вот его отладка
0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds32321 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 13:19:42 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.50-30.00 DS3231_T_1-st-byte=30 13:19:55 3 6 2021 20 DS3231_T-2byte=30.0 F 45.50 DS3231_T=30.0 13:20:00 3 6 2021 20 DS3231_T-2byte=30.0 F 45.50 DS3231_T=30.0 13:21:00 3 6 2021 20 DS3231_T-2byte=30.0 F 45.50 DS3231_T=30.0 13:22:00 3 6 2021 20 DS3231_T-2byte=30.64 F 45.50 DS3231_T=30.25 13:23:00 3 6 2021 20 DS3231_T-2byte=30.64 F 45.50 DS3231_T=30.25 13:24:01 3 6 2021 20 DS3231_T-2byte=30.0 F 45.50 DS3231_T=30.0 13:25:00 3 6 2021 20 DS3231_T-2byte=30.64 F 45.50 DS3231_T=30.25 13:26:00 3 6 2021 20 DS3231_T-2byte=30.64 F 45.50 DS3231_T=30.25 13:27:00 3 6 2021 20 DS3231_T-2byte=30.128 F 45.50 DS3231_T=30.50 13:28:00 3 6 2021 20 DS3231_T-2byte=30.128 F 45.50 DS3231_T=30.50 13:29:01 3 6 2021 20 DS3231_T-2byte=30.128 F 45.50 DS3231_T=30.50 13:30:00 3 6 2021 20 DS3231_T-2byte=30.128 F 45.50 DS3231_T=30.50 13:31:00 3 6 2021 20 DS3231_T-2byte=30.64 F 45.50 DS3231_T=30.25 13:32:00 3 6 2021 20 DS3231_T-2byte=30.0 F 45.50 DS3231_T=30.0 13:33:00 3 6 2021 20 DS3231_T-2byte=29.64 F 45.05 DS3231_T=29.25 13:34:01 3 6 2021 20 DS3231_T-2byte=28.128 F 44.60 DS3231_T=28.50 13:35:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:36:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:37:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:38:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:39:01 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:40:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:41:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 13:42:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 13:43:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 13:44:01 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 13:45:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 13:46:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 13:47:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:48:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:49:01 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 13:50:00 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 13:51:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:52:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:53:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:54:01 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 13:55:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 13:56:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 13:57:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 13:58:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 13:59:01 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:00:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:01:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 14:02:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 14:03:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 14:04:01 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:05:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:06:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 14:07:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 14:08:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 14:09:01 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 14:10:00 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 14:11:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 14:12:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:13:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 14:14:01 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:15:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:16:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:17:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 14:18:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 14:19:01 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 14:20:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:21:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:22:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:23:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:24:01 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:25:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 14:26:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:27:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:28:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 14:29:01 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 14:30:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 14:31:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:32:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:33:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:34:01 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 14:35:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 14:36:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 14:37:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 14:38:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 14:39:01 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:40:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 14:41:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 14:42:00 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 14:43:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 14:44:01 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 14:45:00 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 14:46:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:47:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:48:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:49:01 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 14:50:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 14:51:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 14:52:00 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 14:53:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:54:01 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:55:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:56:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:57:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 14:58:00 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 14:59:01 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:00:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:01:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:02:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:03:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:04:01 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:05:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:06:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:07:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:08:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:09:01 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:10:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:11:00 3 6 2021 20 DS3231_T-2byte=28.64 F 44.60 DS3231_T=28.25 15:12:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:13:00 3 6 2021 20 DS3231_T-2byte=28.0 F 44.60 DS3231_T=28.0 15:14:01 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 15:15:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 15:16:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:17:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:18:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 15:19:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:20:01 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:21:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 15:22:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 15:23:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 15:24:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 15:25:01 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 15:26:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 15:27:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 15:28:00 3 6 2021 20 DS3231_T-2byte=27.128 F 44.15 DS3231_T=27.50 15:29:00 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 15:30:01 3 6 2021 20 DS3231_T-2byte=27.192 F 44.15 DS3231_T=27.75 15:31:00 3 6 2021 20 DS3231_T-2byte=27.64 F 44.15 DS3231_T=27.25 15:32:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:33:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 15:34:00 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 15:35:01 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:36:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:37:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:38:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:39:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:40:01 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 15:41:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 15:42:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 15:43:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:44:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:45:01 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 15:46:00 3 6 2021 20 DS3231_T-2byte=27.0 F 44.15 DS3231_T=27.0 15:47:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 15:48:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 15:49:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 15:50:01 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 15:51:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 15:52:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 15:53:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 15:54:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 15:55:01 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 15:56:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 15:57:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 15:58:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 15:59:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 16:00:01 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 16:01:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:02:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:03:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:04:00 3 6 2021 20 DS3231_T-2byte=26.64 F 43.70 DS3231_T=26.25 16:05:01 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 16:06:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 16:07:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 16:08:00 3 6 2021 20 DS3231_T-2byte=26.192 F 43.70 DS3231_T=26.75 16:09:00 3 6 2021 20 DS3231_T-2byte=26.128 F 43.70 DS3231_T=26.50 16:10:01 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:11:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 16:12:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 16:13:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 16:14:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 16:15:01 3 6 2021 20 DS3231_T-2byte=25.0 F 43.25 DS3231_T=25.0 16:16:00 3 6 2021 20 DS3231_T-2byte=25.0 F 43.25 DS3231_T=25.0 16:17:00 3 6 2021 20 DS3231_T-2byte=25.0 F 43.25 DS3231_T=25.0 16:18:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 16:19:00 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 16:20:01 3 6 2021 20 DS3231_T-2byte=25.64 F 43.25 DS3231_T=25.25 16:21:00 3 6 2021 20 DS3231_T-2byte=25.128 F 43.25 DS3231_T=25.50 16:22:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 16:23:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:24:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:25:01 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:26:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:27:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 16:28:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0 16:29:00 3 6 2021 20 DS3231_T-2byte=25.192 F 43.25 DS3231_T=25.75 16:30:00 3 6 2021 20 DS3231_T-2byte=26.0 F 43.70 DS3231_T=26.0
добавляю 3 кнопки на один вход аналоговый. это для установки времени. Хотя проще даже к компьютеру подключить и поставить время. ! пока переиграл и пробую с одной кнопкой – как в исходной программе. Но часы отличаются сильно – 6 ламп статика и 6 штук К155ИД1. Сейчас установка работает на ощупь – кнопку присоединил – чтобы отображались нужные цифры добавляю обработку highlight dimmed blink – то есть переключаю яркость ламп по дополнительному признаку – массив цифр для отображения работает а яркость пока нет.
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } nowMillis = millis(); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data loadNumberArrayTime(); display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.clear(); shifter.write(); //send changes to the chain and display them } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // ************************************************************ void SetSN74141Chip(int num1) { // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { SetSN74141Chip(NumberArray[i]); } if (timer == digitOffTime) { digitOff(); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // ************************************************************ void digitOn(int digit, int value) { switch (digit) { case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); } SetSN74141Chip(value); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // ************************************************************ void digitOff() { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }


в работе вот здесь картинки и видео – уже ведет себя как часы и раз в минуту показывает температуру – с долями градусов на 4 лампах. Установка времени с компа вручную – при загрузке программы пока. * Время с wi fi ставить не буду – под землей например нет gps wi fi и излучения мобильных сетей. В 76 км от Москвы все таки сота есть. А Dallas Maxim на 5 секунд в год ошибается если температура не играет сильно. А вот советский кварц 32767 в термостате – за год полсекунды врет – он стоит в частотомере и включен в розетку постоянно – 12 ватт вроде – это близко к точности атомных часов . А что бы по ним не синхронизироваться – по радио всегда передавали сигналы точного времени – это они!

сделал кнопку работает но на ощупь. Придумываю как сделать эффект затемнения fade – скорее всего не в секундном а в основном цикле 50 или 100 раз в секунду считаю циклы impression per sec и если яркость полная то ничего не делаю – массив как раз в секунду выведен на лампы (6 цифр в виде массива данных ) так они и работают с полной яркостью , а если стоит значение fade – то эта цифра зажигается каждый 7-й 3-й или 2-й цикл – значения ставятся в другом массиве по каждой цифре отдельно. Остальное время гасится. Пробую со 100 раз в секунду – должна программа успевать – shiftout отрабатывает довольно быстро – миллисекунду. проверю – не будет ли сильного моргания. ( переключать высокое транзистором с 2-х линий как вариант 200 поджиг и 135 снижать до 90 вольт)* сделал – подключил оригинальную программу – будет по ней временная диаграмма.
теперь про программирование. с первой попытки запустил все програмки с исходной версии часов на свой вариант дисплея. !! заработали все эффекты. И даже слоты и затемнение. Но – буду скорость увеличивать или яркость – моргает немножко. Оставил свой перебор цифр с максимумом яркости и вывод температуры на 2 секунды. В пользу экономичности – 300 миллиампер как у китайских часов на ИН14 после переделки, ну это будет ночной режим. Сейчас скажу сколько пишет циклов в секунду.. 34-35 чего то маловато – ускорять надо. Вариант 2 то есть как покупные часы.
// что то с морганием надо делать а так все эффекты работают. // для ночного и экономичного режима то что надо. // .. у меня 35.. 36 циклов в секунду - моргает как декатрон но все работает #include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" // .. эти кусочки кода кладем как библиотеку ардуино в каталог библиотек - берем из оригинала /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT ); // set the input pin 1 // add resistor if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } nowMillis = millis(); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter but useless - current set as normal light OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.setAll(HIGH); // off all tubes shifter.write(); //send changes to the chain and display them } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now // ************************************************************ void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) { switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, value); nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, value); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, value); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } } if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position } if (timer == digitSwitchTime) { SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); } if (timer == digitOffTime) { digitOff(i); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // ************************************************************ void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) { switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, value); nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, value); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, value); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 nixie (16, l4); nixie (12, l3); nixie (8, l2); //minutes nixie (4, l1); nixie (0, l0); //hours lamp 1-2 } } OnOff[digit]= 1; // now digit turns on if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster shifter.setAll(HIGH); /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
сделал 2 упрощения. Когда я учился информатики не было, вспомнил что регистры если не сбросить держат информацию – еще когда собирал и настраивал Радио-86 и Синклеры.. вот код – он выполняется 46 раз в секунду и моргания нет от слова вообще. А эффекты работают – все преимущества статики есть. 260 миллиампер от 12 вольт это круто energy class AAA несмотря на плазменные лампы ИН1 в количестве 6 штук. (только это не совсем статика – пробую еще гасить не все цифры а одну только. Статика работает в динамике.)
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT ); // set the input pin 1 // add resistor if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } nowMillis = millis(); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter but useless - current set as normal light OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.setAll(HIGH); // off all tubes shifter.write(); //send changes to the chain and display them } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // test - turn on only current digit (faster) do not change state of another registry bits switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes nixie (4, value); // nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); nixie (8, value); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); nixie (12, value); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { // nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } } /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); SetSN74141Chip(i,NumberArray[i]); } if (timer == digitOffTime) { digitOff(i); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes nixie (4, value); // nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); nixie (8, value); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); nixie (12, value); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { // nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } } OnOff[digit]= 1; // now digit turns on if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster shifter.setAll(HIGH); /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
поправил – гашение только одной цифры – при выключении а не всех . Визуально разница почти не заметна. эффект сдвига первый раз не срабатывает – перебор цифр а во второй раз и дальше нормально. Число месяц и год показывает. Температуру на 2 секунды с перебором на полной яркости оставил . Фоторезистор не проверял – подпрограмма есть, должен работать. Моргания нет по крайней мере я не замечаю сильного. Ток при полной яркости пол ампера, сейчас 260 ма. установка времени с кнопки работает – режим приглушенной яркости слабовато заметен но работает – настроить можно на еще послабее. Зффект слот машины – где то в настройках есть его установка сколько времени цифра крутится – сейчас четверть секунды примерно. * Если отключить режим полной яркости для температуры – можно чуть еще уменьшить анодные резисторы – до 12 килоом, 2 ватта, сейчас анодное 165 -170 вольт.
OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595
в строке 1224 программы запрограммирован перебор 2 режимов на 50 секунде каждой минуты – если включен slots режим. Переключу его раз в 2 минуты число и месяц год и раз 2 минуты температуру. Режим Fade это появление одной цифры и гашение предыдущей – реализован массивом цифр – 6 штук новых и временный массив tempDisplayDigit старых – можно включить вместе с эффектом слот машины – получается на секунду путаница но красиво. вообще после установки времени – там надо дальше переключать 2-секундным нажатием – есть установка параметров по цифрам – установить лучше 08 параметр в единичку . Выбор длинным нажатием и запись а установка коротким. Однорукий бандит – смотри программу – не взводится если ночь и режим затемнения – а то будут 25 секунд яркие вспышки, прожиг ламп. по короткому нажатию вмето времени – на 5 секунд – выводится число месяц год, потом температура – в секундах 11 это значит что с датчика в микросхеме часов. Потом уровень яркости, еще одно нажатие – число циклов в секунду (51 если 6 цифр и 53 если 5 – у меня).
In this mode a short press cycles through the values given in “Time Display Mode”, but always returns to the standard time display after 5 seconds. Time and Date Settings Установка времени - нажимать кнопку секунду. Set minutes. Each short press will advance the minute. The minutes roll over back to 0 ffter reaching 59 minutes. Each time youset the minute, the seconds is reset to 0. Set Hours. Each short press will advance the hour. Каждое короткое нажатие прибавляет минуту или час, цифры выделены более яркими. The hours roll over back to zero after reaching 12 or 24 (depending on the 12/24 hours mode). Set Day. Each short press will advance the day. The day roll over back to one after reaching the maximum number of days in the month. после нажатия в 2 секунды - установка дня месяца и года. Set Month. Each short press will advance the month. The month roll over back to zero after reaching 12. Set Year. Each short press will advance the year. The year roll over back to 2015 after reaching 2099. Basic Settings “07”flashing настройка по кодам - если моргает код 00 - режим времени 24 или 12 часов 12 or 24 hour time. The hours are displayed in 12 or 24 hour mode. “1” = 12 hour “0” = 24 hour default: 0 “08”flashing Blank leading “0”. Blank out the leading “0” from single digit hours. “1” = blank “0” = don't blank default: 0 перед временем ноль гасить - 1 “09”flashing Scroll back. Use the scroll back (rapid count down) effect when changing from “9” to “0”. “1” = enable “0” = disable default: 1 эффект сдвига цифр -1 лучше 0 “10”flashing режим fade одна цифра за полсекунды меняет другую 0 выкл. 11 flashing Date format. Set the format that the date is displayed in. “0” = YY.MM.DD “1” = MM.DD.YY “2” = DD.MM.YY default: 2 формат числа 23.02.2021 “12”flashing Display blanking. To preserve the tubes, you can set the display to be blanked. Options: “4” = “hours”: Blanks between the start and end hour every day. “5” = “H or weekends”: This blanks all day during the weekends and between the start and end hour every other day. “6” = “H or week days”: This blanks all day during the week days and between the start and end hour every other day. “7” = “H on weekends”: This blanks between the start and end hour on weekends. “8” = “H on week days”: This blanks between the start and end hour on week days. “0” = Don't blank “1” = Weekends“2” = Week days“3” = Always“4” = Hours“5” = H or weekends“6” = H or week days“7” = H on weekends“8” = H on week days default: 0 не выключать лампы на ночь “13”flashing Blanking Hour Start. Hour blanking will start at this hour, on the days set by the Display Blanking Mode. If the display blanking mode does not use hours, this setting is not shown. Default: 00 “14”flashing Blanking Hour End. Hour blanking will end at this hour, on the days set by the Display Blanking Mode. If the display blanking modedoes not use hours, this setting is not shown. Default: 07 если лампы гасятся то с 0 часов до 7 “15”flashing Anti Cathode Poisoning night suppression. The ACP which runs during the night lights the digits up at full brightness, and some people might find this disturbing. Using this setting, you can stop ACP happening when the display is fully dimmed (e.g. at night). “1” = don't do ACP when dimmed “0” = do ACP always default: 0 поставить 1 чтобы ночью не было ярких вспышек - отключить режим анти отравления на ночь. 16 flashing установить в 1 это LDR фоторезистор если припаян 17 flashing выключение на ночь blank mode Special Effects Settings“18”flashing Fade Speed Slower. Each short press will make the fade speed between digits slower. Default: 51 Max: 200 Min: 20 настройка скорости режима смены 2-х цифр “19”flashing Fade Speed Faster. Each short press will make the fade speed between digits faster. Default: 51 Max: 200 Min: 20 “20”flashing Scroll-back Speed Slower. Each short press will make the “scroll-back” speed slower. Default: 6 Max: 40 Min: 1 режим сдвига цифр - работает с настройкой 50 и 4 “21”flashing Scroll-back Speed Faster. Each short press will make the “scroll-back” speed faster. Default: 6 Max: 40 Min: 1 22 flashing режим однорукого бандита - slots machine 1 - включить (красиво) Back Light Settings светодиоды не делал. в оригинальной программе есть - можно добавить - в ардуинку умещается. “12?”flashingBack Light Mode. This sets the mode of the back light.“Fixed” mode will show the back light color according to the Red, Green and Blue channel intensities. “Pulse” will make the intensity of the back light “pulse”, brightening for a second and then darkening for a second, but always respecting the relative intensities set by the Red, Green and Blue channel intensities.“Cycle” fades the back lighting randomly, and does not use the Red, Green and Blue channel intensities. These settings will be skipped if cycle mode is selected.Options “0”, “1” and “2”, do not dim with the bulbs. Options “3”, “4” and “5” do. “0” = Fixed “1” = Pulse “2” = Cycle “3” = Fixed/Dim “4” = Pulse/Dim “5” = Cycle/Dim default: 0 “13?”flashing Red Channel Intensity. Sets the maximum intensity of the red channel back light. This will be dimmed according to the display dimming. If you are in cycle mode, this setting will be skipped.Default: 15Max: 15Min: 0 “14?”flashing Green Channel Intensity. Sets the maximum intensity of the greenchannel back light. This will be dimmed according to the display dimming. If you are in cycle mode, this setting will be skipped. Default: 15 Max: 15 Min: 0 “15?”flashing Blue Channel Intensity. Sets the maximum intensity of the blue channel back light. This will be dimmed according to the display dimming. If you are in cycle mode, this setting will be skipped.Default: 15Max: 15Min: 0 “16?”flashing Cycle Speed. If you are in cycle mode, this controls the speed at which the colors cycle. The higher the number, the slower the colors will change. Default: 10Max: 64 Min: 4 HV Generation Settings (See “HV Settings” note) можно включить как еще источник напряжения - но у меня сделан по-другому на трансформаторе сразу 3 напряжения 165 (200) 490 (600) и 4.3 (5) вольт . Переключаю кнопкой добавляя к 5 лапе mc34063 резистор 30 килоом. “17”flashing HV Target Voltage Higher. Each press sets the HV target voltage higher by 5V. Default: 180 Max: 200 Min: 150 “18”flashing HV Target Voltage Lower. Each press sets the HV target voltage lower by 5V. Default: 180 Max: 200 Min: 150 “19”flashing PWM On Time Longer. This setting controls how long the PWM On pulse is. Normally you should not have to change this, but you can try changing this is the HV generation is noisy or you have unusual tubes. Default: 150 Max: 50 Min: 500 меняется если свист в генераторе высокого или не все лампы установлены. Смотрим теорию преобразователя напряжения - она есть на этой странице. “20”flashing PWM On Time Shorter. This setting controls how long the PWM Onpulse is. Normally you should not have to change this, but you can try changing this is the HV generation is noisy or you have unusual tubes. Default: 150 Max: 50 Min: 500 Information Settings “21?”flashing Current case temperature. Show the current temperature inside the case (used as part of the temperature compensation for the clock crystal). “22?”flashing Clock version. Show the clock software version.Digit Test. Will roll through all digits on all locations to check that the display is healthy. Note “HV Settings”:Before leaving the clock for long periods with a new “HV Generation” setting, check that neither the IRF740 MOSFET nor the 7805 voltage regulator is running too hot. If either of these components gets too hot, either adjust the high voltage settings or add a heat sink. не ставьте 7805 это неправильно особенно 78l05 для ремонта потом все менял и ставил dc-dc 12-5v. Display Blanking Mode During display blanking mode the tubes will be off depending on the display blanking settings, but the “back light” LED will continue to work as usual, telling you that the clock is still running.You can configure the display to blank at weekends, during week days, always or never (the default).In order to display the time during blanking, just press the button, and the time will be displayed for the rest of the minute. Tube Healing Mode прожиг ламп по цифре -работает - вызывается нажатием кнопки 8 секунд. After a long period of time, tube filaments which are not often used (e.g. the “9” on the tens of hours or minutes) can get dim, despite the ACP that is regularly done. If you make a “super-long” press of the button (more than 8 seconds), the clock will enter filament healing mode. All the power will be placed through a single filament of a single digit to clean it. A short press will change the selected filament. Another super-long press or cycling through all the filaments will return the clock to normal. Caution! Don't leave a single filament in this state for an extended period of time. It is a harsh process, and may damage the tube if you leave it in this mode for too long. Normally a few minutes will restore the cathode digit. Factory Reset To reset the clock back to initial settings, hold down the button while powering on. The “tick” LED will flash 10 times to signal that the reset has been done.Everything will be reset back to the factory default state. если запутались нажмите кнопку при включении - установятся начальные настройки. External power supply The perfect voltage for the external power supply is 7.5V or 9V DC. You can use 12V DC.If you use more than 12V be aware that you might have to provide a heat sink for the power components and adjust the HV voltage generation. It is not advised to use more than 12V.
А я сделал 53 цикла в секунду. Еще оптимизация! через ShiftOut напрямую гашение чифры. Еще есть вариант для ускорения – при включении цифры по таймеру – надо проверить какие погашены и выключить их сразу же- иначе будет белиберда. Это после переменной ведущей *учет – 3064 строка. https://discord.gg/B8uJz7bE6w Пытаюсь ускорить внутренний цикл – он 1000 : оборотов по каждой цифре – если задать в настройках 500 то почему то гашение цифр неправильно идет. За секунду получается 50000 раз цифра вспыхивает или гаснет – вот возможности ардуинки – да еще чуть – микросекунда – тратится на Shifter – надо 3 регистра или 24 бита записать последовательно. Смотрел код Shifter он очень быстрый. 51 больших циклов в секунду – если 6 ламп загораются, это достаточно чтобы не заметно было моргание. Или заведу самый простой режим статики – без гашения цифр , в статике потребление 6 ватт а яркость ну не сильно ярче – в полтора раза. Будет темно – включу 2 по 18 килоом 2 ватта в параллель на анод * 14 ватт это если включится в статике будет синее свечение в лампе это сильно перебор – как на фото с лампами на баночке с жидкостью для розжига.
Регулировка яркости работает в динамике конечно – OutputDisplay подпрограмма – вот так – задается число (1000) – во внутреннем цикле сколько раз за каждый проход это число timer увеличивается – до этого значения с нуля. Из 100 циклов лампа горит во всех 1000 – полная яркость, если горит в 500 циклах – наполовину. Если в 30 из 1000 – совсем слабо (dimmed) – minDim.
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT_PULLUP ); // set the input pin 1 // add resistor if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } nowMillis = millis(); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { if (debug){ Serial.println(" butt 2s "); } // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { if (debug){ Serial.println(" button 1s p-r "); } currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter but useless - current set as normal light OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage //checkHVVoltage(); // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); /* nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.setAll(HIGH); // off all tubes shifter.write(); //send changes to the chain and display them */ } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now (OK) // 46 impression per sec // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // test - turn on only current digit (faster) do not change state of another registry bits switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes nixie (4, value); // nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); nixie (8, value); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); nixie (12, value); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { // nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } } /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; /* byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds */ // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); SetSN74141Chip(i,NumberArray[i]); } if (timer == digitOffTime) { digitOff(i); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // nixie (20, l5); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes nixie (4, value); // nixie (0, l0); //hours lamp 1-2 } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); nixie (8, value); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { // nixie (20, l5); //seconds - lamp 5 -6 // nixie (16, l4); nixie (12, value); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { // nixie (20, l5); //seconds - lamp 5 -6 nixie (16, value); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 // nixie (16, l4); // nixie (12, l3); // nixie (8, l2); //minutes // nixie (4, l1); // nixie (0, l0); //hours lamp 1-2 } } OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster //shifter.setAll(HIGH); int j=i*4; shifter.setPin(j, HIGH); shifter.setPin(j+1, HIGH); shifter.setPin(j+2, HIGH); shifter.setPin(j+3, HIGH); /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
а вот этот код добавляет вывод температуры на 15 секунде – использует transition.h вывод 21 75 11 означает что 21 и 75 сотых градуса а 11 это что температура. почему то в первый раз этот эффект transition не срабатывает – скорости что ли не хватает ил и переменная какая не так.
} else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (second() == 15) { // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode();
наверно правильная настройка 0 07 . 1 08 . 1 09 . 0 10 . 0 11 . 1 15 . 1 16 . 2 17. 60 18 . 4 20 . (4 21) 1 22.
Эффект fade отключает это и включает сдвиг как у бегущей строки, а перебор цифры при переключении есть (slots machine). Уточню – описание возможно от другой версии. температура на 15 секунде это не в настройках а вот этот кусочек кода сверху – сравнить с предыдущим. в программе поднял яркость в секции фоторезистора на побольше почти на максимум, как запаяю фоторезистор там есть подстройка.
код как у бегущей строки перенос цифр transition
transition.h #ifndef Transition_h #define Transition_h #include "Arduino.h" #include "DisplayDefs.h" extern byte NumberArray[]; extern byte displayType[]; extern boolean scrollback; class Transition { public: Transition(int, int, int); void start(unsigned long); boolean isMessageOnDisplay(unsigned long); void updateRegularDisplaySeconds(int seconds); boolean scrollMsg(unsigned long); boolean scrambleMsg(unsigned long); boolean scrollInScrambleOut(unsigned long); void setRegularValues(); void setAlternateValues(); void loadRegularValues(); void loadAlternateValues(); void saveCurrentDisplayType(); void restoreCurrentDisplayType(); private: int _effectInDuration; int _effectOutDuration; int _holdDuration; unsigned long _started; unsigned long _end; byte _regularDisplay[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; byte _alternateDisplay[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; boolean _savedScrollback; byte _savedDisplayType[DIGIT_COUNT] = {FADE, FADE, FADE, FADE, FADE, FADE}; unsigned long getEnd(); int scroll(int8_t); int scramble(int, byte, byte); unsigned long hash(unsigned long); }; #endif transition.cpp /** * A class that displays a message by scrolling it into and out of the display * * Thanks judge! */ #include "Arduino.h" #include "Transition.h" Transition::Transition(int effectInDuration, int effectOutDuration, int holdDuration) { _effectInDuration = effectInDuration; _effectOutDuration = effectOutDuration; _holdDuration = holdDuration; _started = 0; _end = 0; } void Transition::start(unsigned long now) { if (_end < now) { _started = now; _end = getEnd(); saveCurrentDisplayType(); } // else we are already running! } boolean Transition::isMessageOnDisplay(unsigned long now) { return (now < _end); } // we need to get the seconds updated, otherwise we show the old // time at the end of the stunt void Transition::updateRegularDisplaySeconds(int seconds) { _regularDisplay[5] = seconds % 10; _regularDisplay[4] = seconds / 10; } boolean Transition::scrollMsg(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); // Scroll -1 -> -DIGIT_COUNT scroll(-(msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration - 1); } else if (msCount < _effectInDuration * 2) { loadAlternateValues(); // Scroll (DIGIT_COUNT-1) -> 0 scroll((DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); // Scroll 1 -> DIGIT_COUNT scroll(((msCount - _holdDuration) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); // Scroll 0 -> -(DIGIT_COUNT-1) scroll(((msCount - _holdDuration) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration - (DIGIT_COUNT-1)); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } boolean Transition::scrambleMsg(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); scramble(msCount, (DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration, DIGIT_COUNT); } else if (msCount < _effectInDuration * 2) { loadAlternateValues(); scramble(msCount, 0, (DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); scramble(msCount, 0, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); scramble(msCount, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1, DIGIT_COUNT); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } boolean Transition::scrollInScrambleOut(unsigned long now) { if (now < _end) { int msCount = now - _started; if (msCount < _effectInDuration) { loadRegularValues(); scroll(-(msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration - 1); } else if (msCount < _effectInDuration * 2) { restoreCurrentDisplayType(); loadAlternateValues(); scroll((DIGIT_COUNT-1) - (msCount % _effectInDuration) * DIGIT_COUNT / _effectInDuration); } else if (msCount < _effectInDuration * 2 + _holdDuration) { loadAlternateValues(); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration) { loadAlternateValues(); scramble(msCount, 0, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1); } else if (msCount < _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2) { loadRegularValues(); scramble(msCount, ((msCount - _holdDuration - _effectInDuration * 2) % _effectOutDuration) * DIGIT_COUNT / _effectOutDuration + 1, DIGIT_COUNT); } else { _end = 0; } return true; // we are still running } return false; // We aren't running } /** * +ve scroll right * -ve scroll left */ int Transition::scroll(int8_t count) { byte copy[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; memcpy(copy, NumberArray, sizeof(copy)); int8_t offset = 0; int8_t slope = 1; if (count < 0) { count = -count; offset = (DIGIT_COUNT-1); slope = -1; } for (byte i=0; i<DIGIT_COUNT; i++) { if (i < count) { displayType[offset + i * slope] = BLANKED; } if (i >= count) { NumberArray[offset + i * slope] = copy[offset + (i-count) * slope]; } } return count; } unsigned long Transition::hash(unsigned long x) { x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; return x; } // In these functions we want something that changes quickly // hence msCount/20. Plus it needs to be different for different // indices, hence +i. Plus it needs to be 'random', hence hash function int Transition::scramble(int msCount, byte start, byte end) { for (int i=start; i < end; i++) { NumberArray[i] = hash(msCount / 20 + i) % 10; } return start; } void Transition::setRegularValues() { memcpy(_regularDisplay, NumberArray, sizeof(_regularDisplay)); } void Transition::setAlternateValues() { memcpy(_alternateDisplay, NumberArray, sizeof(_alternateDisplay)); } void Transition::loadRegularValues() { memcpy(NumberArray, _regularDisplay, sizeof(_regularDisplay)); } void Transition::loadAlternateValues() { memcpy(NumberArray, _alternateDisplay, sizeof(_alternateDisplay)); } void Transition::saveCurrentDisplayType() { memcpy(_savedDisplayType, displayType, sizeof(_savedDisplayType)); _savedScrollback = scrollback; scrollback = false; } void Transition::restoreCurrentDisplayType() { memcpy(displayType, _savedDisplayType, sizeof(_savedDisplayType)); scrollback = _savedScrollback; } unsigned long Transition::getEnd() { return _started + _effectInDuration * 2 + _holdDuration + _effectOutDuration * 2; }
кое что по схемам. Напоминаю что блок питания работает по законам физики и чтобы его сделать понадобится математика, а так проще сделать как в оригинальной конструкции на ардуино. В чем разница – вот который на карандашном рисунке берет от 12 вольт 200 миллиампер а выдает 2.39 ватта и может брать при прожиге всех ламп сразу 2 ампера, выдавая 22 ватта в нагрузку то есть у него эффективность или кпд 89 – 98 процентов. На таком превышении мощности в 4 раза радиатор транзистора и катушка вч транса чуть чуть греются. А вот на ардуино я не проверял как работает. ( по деталям ну почти так же должен, pwm и рассчет там использовался. На MC34063 даже не совсем pwm а скорее частотно импульсная модуляция что на результат не влияет да и 30-120 килогерц никакого свиста, это при неподходящем дросселе свист.)

рисунок неплохого художника – посмотрев в зеркало. Кокошник из одуванчиков где?
Кое что из магии. если быстро поводить глазами.. не поводить , сильное напряжение мышц с разных сторон глаза а потом с тренировкой не сильное. Как в журнале Наука и жизнь за 70-е года – там советовалось посмотреть стерео фотографии – без очков – просто разделив их ладошкой- на странице было две или четыре почти одинаковых фото, только с хитринкой – одно снято фотографом с левой ноги а второе с правой – переставив фотоаппарат на полметра влево вправо. Получается мощнейший стерео эффект – все фото объемные. Даже кино такое показывали – не то что сейчас с очками за 300 рублей.. Так вот, если делать это не первый раз тренируясь — так глазки могут двигаться раз 300 в секунду а может и больше и это безопасно. а вот слабо посмотреть в таком режиме на светодиоды – один к драйверу управления hv – с mc34063 и линейку на светодиодах – srclk rclk serial_data sda scl. Да как осцилла с разверткой получается – в первом телеке был шестигранник он и вращался и отражал луч развертки или не шестигранник путаю с лазерным принтером.. короче сигнал с 34063 распадается на цепочку вспышек – там 120-300 Килогерц! а последовательные данные с синхрой с тактовыми.. с накладкой чуть чуть и почти рядом вспышечки это вообще мегагерц почти. _по кругу еще поводить_ тысяча вспышек за Микросекунду и видно невооруженным глазом!!
на несколько исправлений код различается и рядом сразу оригинальный – но там автор добавил выключение ламп по ик датчику приближения. Proximity alert / смотрим американское кино про чужих. а американцы получили 2 серии Брат и Брат2 с неплохим переводом.
//********************************************************************************** //* Main code for an Arduino based Nixie clock. Features: * //* - WiFi Clock interface for the WiFiModule OR * //* - Real Time Clock interface for DS3231 * //* - Digit fading with configurable fade length * //* - Digit scrollback with configurable scroll speed * //* - Configuration stored in EEPROM * //* - Low hardware component count (as much as possible done in code) * //* - Single button operation with software debounce * //* - Single K155ID1 for digit display (other versions use 2 or even 6!) * //* - Automatic dimming, using a Light Dependent Resistor * //* - RGB back light management using individually addressable WS2812B * //* - PIR sensor to turn off display when no one is around * //* * //* nixie@protonmail.ch * //* * //********************************************************************************** //********************************************************************************** // Standard Libraries #include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> // Clock specific libraries, install these with "Sketch -> Include Library -> Add .ZIP library // using the ZIP files in the "libraries" directory #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) #include <TimeLib.h> // http://playground.arduino.cc/code/time (Margolis 1.5.0) #include <Adafruit_NeoPixel.h> // https://github.com/adafruit/Adafruit_NeoPixel (Adafruit 1.1.8) // Other parts of the code, broken out for clarity #include "ClockButton.h" #include "Transition.h" #include "DisplayDefs.h" #include "I2CDefs.h" #define FWV2 // "REV3" for Modular Rev3 "FWV2" for ClassicRev6 and ModularRev3.01 //********************************************************************************** //********************************************************************************** //* Constants * //********************************************************************************** //********************************************************************************** #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again #define EE_PIR_TIMEOUT_LO 37 // The PIR timeout time in S, low byte #define EE_PIR_TIMEOUT_HI 38 // The PIR timeout time in S, high byte #define EE_PIR_PULLUP 39 // If we use the internal pullup on the PIR pin (false = use 3V3 PIR, PIR connected, true = no PIR connected or 5V PIR) #define EE_MIN_DIM_LO 40 // The minimum dimming value, low byte #define EE_MIN_DIM_HI 41 // The minimum dimming value, high byte #define EE_DP_ENABLE 42 // Control the decimal points // Software version shown in config menu #define SOFTWARE_VERSION 358 // how often we make reference to the external time provider #define READ_TIME_PROVIDER_MILLIS 60000 // Update the internal time provider from the external source once every minute // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 500 // Minimum value we can set to #define MIN_DIM_DEFAULT 100 // The default minimum dim count #define MIN_DIM_MIN 100 // The minimum dim count #define MIN_DIM_MAX 500 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 // The number of dispay impessions we need to fade by default // 100 is about 1 second #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 #define COLOUR_CNL_MAX 15 #define COLOUR_RED_CNL_DEFAULT 15 #define COLOUR_GRN_CNL_DEFAULT 0 #define COLOUR_BLU_CNL_DEFAULT 0 #define COLOUR_CNL_MIN 0 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // skipped if not using hour blanking #define MODE_HR_BLNK_END 14 // skipped if not using hour blanking #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // PIR #define MODE_PIR_TIMEOUT_UP 23 // #define MODE_PIR_TIMEOUT_DOWN 24 // // Back light #define MODE_BACKLIGHT_MODE 25 // #define MODE_RED_CNL 26 // #define MODE_GRN_CNL 27 // #define MODE_BLU_CNL 28 // #define MODE_CYCLE_SPEED 29 // // HV generation - Not Available over I2C #define MODE_TARGET_HV_UP 30 // #define MODE_TARGET_HV_DOWN 31 // #define MODE_PULSE_UP 32 // #define MODE_PULSE_DOWN 33 // // Minimum dimming value for old tubes #define MODE_MIN_DIM_UP 34 // #define MODE_MIN_DIM_DOWN 35 // // Anti-ghosting for old tubes - Not Available over I2C #define MODE_ANTI_GHOST_UP 36 // #define MODE_ANTI_GHOST_DOWN 37 // // Use the PIR pin pullup resistor - Not Available over I2C #define MODE_USE_PIR_PULLUP 38 // 1 = use Pullup #define USE_PIR_PULLUP_DEFAULT true #define MODE_ENABLE_DP 39 // Set the decimal points // Temperature #define MODE_TEMP 40 // Show the temperature // Software Version #define MODE_VERSION 41 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 42 #define MODE_MAX 42 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_ALL 3 // Use blanking for tubes, LEDs and separators #define BLANK_MODE_MAX BLANK_MODE_BOTH #define BLANK_MODE_DEFAULT BLANK_MODE_ALL #define BACKLIGHT_MIN 0 #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_COLOUR_TIME 6 // use "ColourTime" - different colours for each digit value #define BACKLIGHT_COLOUR_TIME_DIM 7 // use "ColourTime" - dims with bulb dimming #define BACKLIGHT_MAX 7 #define BACKLIGHT_DEFAULT 4 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define PIR_TIMEOUT_MIN 60 // 1 minute in seconds #define PIR_TIMEOUT_MAX 3600 // 1 hour in seconds #define PIR_TIMEOUT_DEFAULT 300 // 5 minutes in seconds #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define DP_ENABLE_MIN 0 #define DP_ENABLE_ALL 0 // Use all DPs #define DP_ENABLE_AMPM 1 // Use only he AM/PM indicator (no PIR) #define DP_ENABLE_NONE 2 // Use no DPs - all off #define DP_ENABLE_MAX DP_ENABLE_NONE #define DP_ENABLE_DEFAULT DP_ENABLE_AMPM // RTC address #define RTC_I2C_ADDRESS 0x68 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true //********************************************************************************** //********************************************************************************** //* Variables * //********************************************************************************** //********************************************************************************** // ***** Pin Defintions ****** Pin Defintions ****** Pin Defintions ****** // SN74141/K155ID1 // These are now managed directly on PORT B, we don't use digitalWrite() for these #define ledPin_0_a 13 // package pin 19 // PB5 #define ledPin_0_b 10 // package pin 16 // PB2 #define ledPin_0_c 8 // package pin 14 // PB0 #define ledPin_0_d 12 // package pin 18 // PB4 // anode pins #ifdef REV3 #define ledPin_a_1 A3 // high - Hours tens // Package pin 26 // PC3 // Analog or digital input for PIR #else #define ledPin_a_1 7 // high - Hours tens // package pin 13 // PD7 #endif #define ledPin_a_2 4 // - Hours units // package pin 6 // PD4 #define ledPin_a_3 3 // - Mins tens // package pin 5 // PD3 #define ledPin_a_4 2 // - Mins units // package pin 4 // PD2 #define ledPin_a_5 1 // - Secs tens // package pin 3 // PD1 #define ledPin_a_6 0 // low - Secs units // package pin 2 // PD0 // button input #define inputPin1 A2 // Package pin 25 // PC2 // Analog or digital input for button. // PIR input #ifdef REV3 #define pirPin 7 // package pin 13 // PD7 #else #define pirPin A3 // Package pin 26 // PC3 // Analog or digital input for PIR #endif // PWM pin used to drive the DC-DC converter #define hvDriverPin 9 // package pin 15 // PB1 // Tick led - PWM capable #define tickLed 11 // package pin 17 // PB3 // Decimal point - PWM capable #define DP 5 // package pin 11 // PD5 // PWM capable output for backlight - Neo Pixel chain #define LED_DOUT 6 // package pin 12 // PD6 #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler byte decodeDigit[16] = {2, 3, 7, 6, 4, 5, 1, 0, 9, 8, 10, 10, 10, 10, 10, 10}; // Settings for ZM1000 // byte decodeDigit[16] = {6, 9, 8, 2, 0, 1, 5, 4, 3, 7, 10, 10, 10, 10, 10, 10}; // Driver pins for the anodes byte anodePins[DIGIT_COUNT] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; // ************************ Display management ************************ byte NumberArray[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; byte displayType[DIGIT_COUNT] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module byte valueDisplayTime = 0; byte valueToShow[3] = {0, 0, 0}; byte valueDisplayType[3] = {0x33, 0x33, 0x33}; // All normal by default // Decimal point indicators boolean dpArray[DIGIT_COUNT] = {false, false, false, false, false, false}; // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = false; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; boolean blankSeparators = false; byte dpEnable = DP_ENABLE_DEFAULT; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; boolean usePIRPullup = true; // ************************ Clock variables ************************ // RTC, uses Analogue pins A4 (SDA) and A5 (SCL) DS3231 Clock; // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; // PIR unsigned long pirTimeout = PIR_TIMEOUT_DEFAULT; unsigned long pirLastSeen = 0; boolean triggeredThisSec = false; byte useRTC = false; // true if we detect an RTC byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi // **************************** LED management *************************** boolean upOrDown; // Blinking colons led in settings modes int ledBlinkCtr = 0; int ledBlinkNumber = 0; byte backlightMode = BACKLIGHT_DEFAULT; // Back light intensities byte redCnl = COLOUR_RED_CNL_DEFAULT; byte grnCnl = COLOUR_GRN_CNL_DEFAULT; byte bluCnl = COLOUR_BLU_CNL_DEFAULT; byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; int colors[3]; // individual channel colours for the LEDs byte ledR[DIGIT_COUNT]; byte ledG[DIGIT_COUNT]; byte ledB[DIGIT_COUNT]; // set up the NeoPixel library Adafruit_NeoPixel leds = Adafruit_NeoPixel(6, LED_DOUT, NEO_GRB + NEO_KHZ800); // Strategy 3 int changeSteps = 0; byte currentColour = 0; int impressionsPerSec = 0; int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; //********************************************************************************** //********************************************************************************** //* Setup * //********************************************************************************** //********************************************************************************** void setup() { pinMode(ledPin_0_a, OUTPUT); pinMode(ledPin_0_b, OUTPUT); pinMode(ledPin_0_c, OUTPUT); pinMode(ledPin_0_d, OUTPUT); pinMode(ledPin_a_1, OUTPUT); pinMode(ledPin_a_2, OUTPUT); pinMode(ledPin_a_3, OUTPUT); pinMode(ledPin_a_4, OUTPUT); pinMode(ledPin_a_5, OUTPUT); pinMode(ledPin_a_6, OUTPUT); pinMode(tickLed, OUTPUT); pinMode(LED_DOUT, OUTPUT); pinMode(DP, OUTPUT); pinMode(pirPin, INPUT); // The LEDS sometimes glow at startup, it annoys me, so turn them completely off analogWrite(tickLed, 0); setAllLEDs(0,0,0); // NOTE: // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT ); // set the input pin 1 digitalWrite(inputPin1, HIGH); // set pin 1 as a pull up resistor. // Set the driver pin to putput pinMode(hvDriverPin, OUTPUT); /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the LED output leds.begin(); // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } // Read EEPROM values readEEPROMValues(); // Not setting the pullup resistor allows us to use 3V3 devices (e.g. RCWL-0516) digitalWrite(pirPin, usePIRPullup); // set pull up resistor - if no PIR connected, default to "triggered" // set our PWM profile setPWMOnTime(pwmOn); setPWMTopTime(pwmTop); // Set the target voltage rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // HV GOOOO!!!! TCCR1A = tccrOn; if (doTestPattern) { boolean oldUseLDR = useLDR; byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // set backlights to change with the displayed digits backlightMode = BACKLIGHT_COLOUR_TIME; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); checkHVVoltage(); setLeds(); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; } } useLDR = oldUseLDR; backlightMode = oldBacklightMode; } // reset the LEDs setLeds(); // Set up the HVG if we need to if (EEPROM.read(EE_HVG_NEED_CALIB)) { calibrateHVG(); // Save the PWM values EEPROM.write(EE_PULSE_LO, pwmOn % 256); EEPROM.write(EE_PULSE_HI, pwmOn / 256); EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); // Mark that we don't need to do this next time EEPROM.write(EE_HVG_NEED_CALIB, false); } // and return it to target voltage so we can regulate the PWM on time rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); setTime(12, 34, 56, 1, 3, 2019); getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } //********************************************************************************** //********************************************************************************** //* Main loop * //********************************************************************************** //********************************************************************************** boolean millisNotSet = true; void loop() { nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; // ------------------------------------------------------------------------------- if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { performOncePerDayProcessing(); } performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // ------------------------------------------------------------------------------- // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 1; } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 50) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode digitOn(digitBurnDigit, digitBurnValue); } // Prepare the tick and backlight LEDs setLeds(); } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean pirBlanked = checkPIR(nowMillis); boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = (nativeBlanked || pirBlanked) && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Decrement the value display counter // 0xff means "forever", so don't decrement it if ((valueDisplayTime > 0) && (valueDisplayTime < 0xff)) { valueDisplayTime--; } // Slow regulation of the voltage checkHVVoltage(); // feed the watchdog wdt_reset(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) getRTCTime(); } // AM/PM indicator - show if we are in 12H mode and it is PM if ((dpEnable == DP_ENABLE_ALL) || (dpEnable == DP_ENABLE_AMPM)) { dpArray[1] = hourMode && (hour() > 12); } else { dpArray[1] = false; } } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } // ************************************************************ // Called once per day // ************************************************************ void performOncePerDayProcessing() { } // ************************************************************ // Set the seconds tick led(s) and the back lights // ************************************************************ void setLeds() { int secsDelta; if (upOrDown) { secsDelta = (nowMillis - lastCheckMillis); } else { secsDelta = 1000 - (nowMillis - lastCheckMillis); } // calculate the PWM factor, goes between minDim% and 100% float dimFactor = (float) digitOffCount / (float) DIGIT_DISPLAY_OFF; float pwmFactor = (float) secsDelta / (float) 1000.0; // Tick led output analogWrite(tickLed, getLEDAdjusted(255, pwmFactor, dimFactor)); if (blankLEDs) { setAllLEDs( getLEDAdjusted(0, 1, 1), getLEDAdjusted(0, 1, 1), getLEDAdjusted(0, 1, 1)); } else { // RGB Backlight PWM led output if (currentMode == MODE_TIME) { switch (backlightMode) { case BACKLIGHT_FIXED: setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], 1, 1), getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, 1), getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, 1)); break; case BACKLIGHT_PULSE: setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, 1), getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, 1), getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, 1)); break; case BACKLIGHT_CYCLE: cycleColours3(colors); setAllLEDs( getLEDAdjusted(colors[0], 1, 1), getLEDAdjusted(colors[1], 1, 1), getLEDAdjusted(colors[2], 1, 1)); break; case BACKLIGHT_FIXED_DIM: setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], 1, dimFactor), getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, dimFactor), getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, dimFactor)); break; case BACKLIGHT_PULSE_DIM: setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, dimFactor), getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, dimFactor), getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, dimFactor)); break; case BACKLIGHT_CYCLE_DIM: cycleColours3(colors); setAllLEDs( getLEDAdjusted(colors[0], 1, dimFactor), getLEDAdjusted(colors[1], 1, dimFactor), getLEDAdjusted(colors[2], 1, dimFactor)); break; case BACKLIGHT_COLOUR_TIME: for (int i = 0 ; i < 6 ; i++) { ledR[5-i] = getLEDAdjusted(colourTimeR[NumberArray[i]],1,1); ledG[5-i] = getLEDAdjusted(colourTimeG[NumberArray[i]],1,1); ledB[5-i] = getLEDAdjusted(colourTimeB[NumberArray[i]],1,1); } outputLEDBuffer(); break; case BACKLIGHT_COLOUR_TIME_DIM: for (int i = 0 ; i < 6 ; i++) { ledR[5-i] = getLEDAdjusted(colourTimeR[NumberArray[i]],1,dimFactor); ledG[5-i] = getLEDAdjusted(colourTimeG[NumberArray[i]],1,dimFactor); ledB[5-i] = getLEDAdjusted(colourTimeB[NumberArray[i]],1,dimFactor); } outputLEDBuffer(); break; } } else { // Settings modes ledBlinkCtr++; if (ledBlinkCtr > 40) { ledBlinkCtr = 0; ledBlinkNumber++; if (ledBlinkNumber > nextMode) { // Make a pause ledBlinkNumber = -2; } } if ((ledBlinkNumber <= nextMode) && (ledBlinkNumber > 0)) { if (ledBlinkCtr < 3) { setAllLEDs(255,255,255); } else { setAllLEDs(0,0,0); } } } } } // ************************************************************ // Check the PIR status. If we don't have a PIR installed, we // don't want to respect the pin value, because it would defeat // normal day blanking. The first time the PIR takes the pin low // we mark that we have a PIR and we should start to respect // the sensor. // Returns true if PIR sensor is installed and we are blanked // ************************************************************ boolean checkPIR(unsigned long nowMillis) { boolean pirvalue = (digitalRead(pirPin) == HIGH); boolean useDPs = (dpEnable == DP_ENABLE_ALL); dpArray[5] = pirvalue && useDPs; if (pirvalue) { pirLastSeen = nowMillis; return false; } else { if (nowMillis > (pirLastSeen + (pirTimeout * 1000))) { dpArray[4] = false; return true; } else { dpArray[4] = true && useDPs; return false; } } } // ************************************************************ // Set back light LEDs to the same colour // ************************************************************ void setAllLEDs(byte red, byte green, byte blue) { for (int i = 0 ; i < DIGIT_COUNT ; i++) { ledR[i] = red; ledG[i] = green; ledB[i] = blue; } outputLEDBuffer(); } // ************************************************************ // Put the led buffers out // ************************************************************ void outputLEDBuffer() { for (int i = 0 ; i < DIGIT_COUNT ; i++) { leds.setPixelColor(i, leds.Color(ledR[i], ledG[i], ledB[i])); } leds.show(); } // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_PIR_TIMEOUT_UP: case MODE_PIR_TIMEOUT_DOWN: { loadNumberArrayConfInt(pirTimeout, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_BACKLIGHT_MODE: { loadNumberArrayConfInt(backlightMode, displayMode); displayConfig(); break; } case MODE_RED_CNL: { if ((backlightMode == BACKLIGHT_CYCLE) || (backlightMode == BACKLIGHT_CYCLE_DIM)) { // Skip if we are in cycle mode setNewNextMode(MODE_CYCLE_SPEED); } loadNumberArrayConfInt(redCnl, displayMode); displayConfig(); break; } case MODE_GRN_CNL: { loadNumberArrayConfInt(grnCnl, displayMode); displayConfig(); break; } case MODE_BLU_CNL: { loadNumberArrayConfInt(bluCnl, displayMode); displayConfig(); break; } case MODE_CYCLE_SPEED: { if ((backlightMode != BACKLIGHT_CYCLE) && (backlightMode != BACKLIGHT_CYCLE_DIM)) { // Show only if we are in cycle mode setNewNextMode(MODE_TARGET_HV_UP); } loadNumberArrayConfInt(cycleSpeed, displayMode); displayConfig(); break; } case MODE_TARGET_HV_UP: case MODE_TARGET_HV_DOWN: { loadNumberArrayConfInt(hvTargetVoltage, displayMode); displayConfig(); break; } case MODE_PULSE_UP: case MODE_PULSE_DOWN: { loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_USE_PIR_PULLUP: { loadNumberArrayConfBool(usePIRPullup, displayMode); displayConfig(); break; } case MODE_ENABLE_DP: { loadNumberArrayConfInt(dpEnable, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_VERSION: { loadNumberArrayConfInt(SOFTWARE_VERSION, displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_MODE_VERSION) { loadNumberArrayConfInt(SOFTWARE_VERSION, 0); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_PIR_TIMEOUT_UP: { if (button1.isButtonPressedAndReleased()) { pirTimeout+=10; if (pirTimeout > PIR_TIMEOUT_MAX) { pirTimeout = PIR_TIMEOUT_MIN; } } loadNumberArrayConfInt(pirTimeout, displayMode); displayConfig(); break; } case MODE_PIR_TIMEOUT_DOWN: { if (button1.isButtonPressedAndReleased()) { pirTimeout-=10; if (pirTimeout < PIR_TIMEOUT_MIN) { pirTimeout = PIR_TIMEOUT_MAX; } } loadNumberArrayConfInt(pirTimeout, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_BACKLIGHT_MODE: { if (button1.isButtonPressedAndReleased()) { backlightMode++; if (backlightMode > BACKLIGHT_MAX) { backlightMode = BACKLIGHT_MIN; } } loadNumberArrayConfInt(backlightMode, displayMode); displayConfig(); break; } case MODE_RED_CNL: { if (button1.isButtonPressedAndReleased()) { redCnl++; if (redCnl > COLOUR_CNL_MAX) { redCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(redCnl, displayMode); displayConfig(); break; } case MODE_GRN_CNL: { if (button1.isButtonPressedAndReleased()) { grnCnl++; if (grnCnl > COLOUR_CNL_MAX) { grnCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(grnCnl, displayMode); displayConfig(); break; } case MODE_BLU_CNL: { if (button1.isButtonPressedAndReleased()) { bluCnl++; if (bluCnl > COLOUR_CNL_MAX) { bluCnl = COLOUR_CNL_MIN; } } loadNumberArrayConfInt(bluCnl, displayMode); displayConfig(); break; } case MODE_CYCLE_SPEED: { if (button1.isButtonPressedAndReleased()) { cycleSpeed = cycleSpeed + 2; if (cycleSpeed > CYCLE_SPEED_MAX) { cycleSpeed = CYCLE_SPEED_MIN; } } loadNumberArrayConfInt(cycleSpeed, displayMode); displayConfig(); break; } case MODE_TARGET_HV_UP: { if (button1.isButtonPressedAndReleased()) { hvTargetVoltage += 5; if (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_MIN; } } loadNumberArrayConfInt(hvTargetVoltage, displayMode); rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); displayConfig(); break; } case MODE_TARGET_HV_DOWN: { if (button1.isButtonPressedAndReleased()) { hvTargetVoltage -= 5; if (hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_MAX; } } loadNumberArrayConfInt(hvTargetVoltage, displayMode); rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); displayConfig(); break; } case MODE_PULSE_UP: { if (button1.isButtonPressedAndReleased()) { pwmOn += 10; if (pwmOn > PWM_PULSE_MAX) { pwmOn = PWM_PULSE_MAX; } setPWMOnTime(pwmOn); } loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_PULSE_DOWN: { if (button1.isButtonPressedAndReleased()) { pwmOn -= 10; if (pwmOn > PWM_PULSE_MAX) { pwmOn = PWM_PULSE_MAX; } setPWMOnTime(pwmOn); } loadNumberArrayConfInt(pwmOn, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: { if (button1.isButtonPressedAndReleased()) { antiGhost += 1; if (antiGhost > ANTI_GHOST_MAX) { antiGhost = ANTI_GHOST_MAX; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; } loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_DOWN: { if (button1.isButtonPressedAndReleased()) { antiGhost -= 1; if (antiGhost < ANTI_GHOST_MIN) { antiGhost = ANTI_GHOST_MIN; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; } loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_USE_PIR_PULLUP: { if (button1.isButtonPressedAndReleased()) { usePIRPullup = !usePIRPullup; } loadNumberArrayConfBool(usePIRPullup, displayMode); digitalWrite(pirPin, usePIRPullup); displayConfig(); break; } case MODE_ENABLE_DP: { if (button1.isButtonPressedAndReleased()) { dpEnable++; if (dpEnable > DP_ENABLE_MAX) { dpEnable = DP_ENABLE_MIN; } } loadNumberArrayConfInt(dpEnable, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_VERSION: { loadNumberArrayConfInt(SOFTWARE_VERSION, displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } // ************************************************************ // output a PWM LED channel, adjusting for dimming and PWM // brightness: // rawValue: The raw brightness value between 0 - 255 // ledPWMVal: The pwm factor between 0 - 1 // dimFactor: The dimming value between 0 - 1 // ************************************************************ byte getLEDAdjusted(float rawValue, float ledPWMVal, float dimFactor) { byte dimmedPWMVal = (byte)(rawValue * ledPWMVal * dimFactor); return dim_curve[dimmedPWMVal]; } // ************************************************************ // Colour cycling 3: one colour dominates // ************************************************************ void cycleColours3(int colors[3]) { cycleCount++; if (cycleCount > cycleSpeed) { cycleCount = 0; if (changeSteps == 0) { changeSteps = random(256); currentColour = random(3); } changeSteps--; switch (currentColour) { case 0: if (colors[0] < 255) { colors[0]++; if (colors[1] > 0) { colors[1]--; } if (colors[2] > 0) { colors[2]--; } } else { changeSteps = 0; } break; case 1: if (colors[1] < 255) { colors[1]++; if (colors[0] > 0) { colors[0]--; } if (colors[2] > 0) { colors[2]--; } } else { changeSteps = 0; } break; case 2: if (colors[2] < 255) { colors[2]++; if (colors[0] > 0) { colors[0]--; } if (colors[1] > 0) { colors[1]--; } } else { changeSteps = 0; } break; } } } //********************************************************************************** //********************************************************************************** //* Utility functions * //********************************************************************************** //********************************************************************************** // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Show the value we got over I2C // ************************************************************ void loadNumberArrayValue() { NumberArray[5] = valueToShow[2] & 0xf; NumberArray[4] = valueToShow[2] >> 4; NumberArray[3] = valueToShow[1] & 0xf; NumberArray[2] = valueToShow[1] >> 4; NumberArray[1] = valueToShow[0] & 0xf; NumberArray[0] = valueToShow[0] >> 4; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // ************************************************************ void SetSN74141Chip(int num1) { // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. // This is the heart of the display processing! // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { digitalWrite(DP, dpArray[i]); if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { SetSN74141Chip(NumberArray[i]); } if (timer == digitOffTime) { digitOff(); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // ************************************************************ void digitOn(int digit, int value) { switch (digit) { #ifdef REV3 case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); #else case 0: PORTD = PORTD | B10000000; break; // PD7 - equivalent to digitalWrite(ledPin_a_1,HIGH); #endif case 1: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 2: PORTD = PORTD | B00001000; break; // PD3 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); } SetSN74141Chip(value); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen off // ************************************************************ void digitOff() { TCCR1A = tccrOff; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster #ifdef REV3 PORTC = PORTC & B11110111; PORTD = PORTD & B11100000; #else PORTD = PORTD & B01100000; #endif } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Display preset // ************************************************************ void loadDisplayConfigValue() { displayType[5] = valueDisplayType[2] & 0xf; displayType[4] = valueDisplayType[2] >> 4; displayType[5] = valueDisplayType[1] & 0xf; displayType[2] = valueDisplayType[1] >> 4; displayType[1] = valueDisplayType[0] & 0xf; displayType[0] = valueDisplayType[0] >> 4; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; blankSeparators = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; blankSeparators = false; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; blankSeparators = false; break; } case BLANK_MODE_ALL: { blankTubes = true; blankLEDs = true; blankSeparators = true; break; } } } else { blankTubes = false; blankLEDs = false; } } void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { setAllLEDs(255,0,0); } if (random(3) == 0) { setAllLEDs(0,255,0); } if (random(3) == 0) { setAllLEDs(0,0,255); } delay(delayVal); digitalWrite(tickLed, LOW); setAllLEDs(0,0,0); delay(delayVal); } // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; } //********************************************************************************** //********************************************************************************** //* RTC Module Time Provider * //********************************************************************************** //********************************************************************************** // ************************************************************ // Get the time from the RTC // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); } // Return back to I2C in slave mode Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); Wire.endTransmission(); Wire.end(); Wire.begin(I2C_SLAVE_ADDR); Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); EEPROM.write(EE_RED_INTENSITY, redCnl); EEPROM.write(EE_GRN_INTENSITY, grnCnl); EEPROM.write(EE_BLU_INTENSITY, bluCnl); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); EEPROM.write(EE_PULSE_LO, pwmOn % 256); EEPROM.write(EE_PULSE_HI, pwmOn / 256); EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_PIR_TIMEOUT_LO, pirTimeout % 256); EEPROM.write(EE_PIR_TIMEOUT_HI, pirTimeout / 256); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); EEPROM.write(EE_PIR_PULLUP, usePIRPullup); EEPROM.write(EE_DP_ENABLE, dpEnable); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } dayBlanking = EEPROM.read(EE_DAY_BLANKING); if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; pirTimeout = EEPROM.read(EE_PIR_TIMEOUT_HI) * 256 + EEPROM.read(EE_PIR_TIMEOUT_LO); if ((pirTimeout < PIR_TIMEOUT_MIN) || (pirTimeout > PIR_TIMEOUT_MAX)) { pirTimeout = PIR_TIMEOUT_DEFAULT; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } blankMode= EEPROM.read(EE_BLANK_MODE); if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } usePIRPullup = EEPROM.read(EE_PIR_PULLUP); dpEnable = EEPROM.read(EE_DP_ENABLE); if ((dpEnable < DP_ENABLE_MIN) || (dpEnable > DP_ENABLE_MAX)) { dpEnable = DP_ENABLE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; backlightMode = BACKLIGHT_DEFAULT; redCnl = COLOUR_RED_CNL_DEFAULT; grnCnl = COLOUR_GRN_CNL_DEFAULT; bluCnl = COLOUR_BLU_CNL_DEFAULT; hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; cycleSpeed = CYCLE_SPEED_DEFAULT; pwmOn = PWM_PULSE_DEFAULT; pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; antiGhost = ANTI_GHOST_DEFAULT; pirTimeout = PIR_TIMEOUT_DEFAULT; useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; usePIRPullup = USE_PIR_PULLUP_DEFAULT; dpEnable = DP_ENABLE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } //********************************************************************************** //********************************************************************************** //* Light Dependent Resistor * //********************************************************************************** //********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } // ****************************************************************** // Routine to set the LEDs // LEDPin // brightens and dims a PWM capable LED // - 0 to 255 ramp up // - 256 to 511 plateau // - 512 to 767 ramp down // ****************************************************************** void checkLEDPWM(byte LEDPin, int step) { if (step > 767) { if (LEDPin == tickLed) { analogWrite(LEDPin, getLEDAdjusted(0, 1, 1)); } else { setAllLEDs(0,0,0); } } else if (step > 512) { if (LEDPin == tickLed) { analogWrite(LEDPin, getLEDAdjusted(255 - (step - 512), 1, 1)); } else { switch (LEDPin) { case 0: setAllLEDs(getLEDAdjusted(255 - (step - 512),1,1),0,0); break; case 1: setAllLEDs(0,getLEDAdjusted(255 - (step - 512),1,1),0); break; case 2: setAllLEDs(0,0,getLEDAdjusted(255 - (step - 512),1,1)); break; } } } else if (step > 255) { if (LEDPin == tickLed) { analogWrite(LEDPin, getLEDAdjusted(255, 1, 1)); } else { switch (LEDPin) { case 0: setAllLEDs(getLEDAdjusted(255,1,1),0,0); break; case 1: setAllLEDs(0,getLEDAdjusted(255,1,1),0); break; case 2: setAllLEDs(0,0,getLEDAdjusted(255,1,1)); break; } } } else if (step > 0) { if (LEDPin == tickLed) { analogWrite(LEDPin, getLEDAdjusted(step, 1, 1)); } else { switch (LEDPin) { case 0: setAllLEDs(getLEDAdjusted(step,1,1),0,0); break; case 1: setAllLEDs(0,getLEDAdjusted(step,1,1),0); break; case 2: setAllLEDs(0,0,getLEDAdjusted(step,1,1)); break; } } } } // ****************************************************************** // Calibrate the HV generator // The idea here is to get the right combination of PWM on and top // time to provide the right high voltage with the minimum power // Consumption. // // Every combination of tubes and external power supply is different // and we need to pick the right PWM total duration ("top") and // PWM on time ("on") to match the power supply and tubes. // Once we pick the "on" time, it is not adjusted during run time. // PWM top is adjusted during run. // // The PWM on time is picked so that we reach just the point that the // inductor goes into saturation - any more time on is just being used // to heat the MOSFET and the inductor, but not provide any voltage. // // We go through two cycles: each time we decrease the PWM top // (increase frequency) to give more voltage, then reduce PWM on // until we notice a drop in voltage. // ****************************************************************** void calibrateHVG() { // *************** first pass - get approximate frequency ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage + 5); setPWMOnTime(PWM_PULSE_DEFAULT); // Calibrate HVGen at full for (int i = 0 ; i < 768 ; i++ ) { loadNumberArraySameValue(8); allBright(); outputDisplay(); checkHVVoltage(); checkLEDPWM(tickLed, i); } // *************** second pass - get on time minimum ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage); // run up the on time from the minimum to where we reach the required voltage setPWMOnTime(PWM_PULSE_MIN); for (int i = 0 ; i < 768 ; i++ ) { //loadNumberArray8s(); loadNumberArrayConfInt(pwmOn, 0); allBright(); outputDisplay(); if (getSmoothedHVSensorReading() < rawHVADCThreshold) { if ((i % 8) == 0 ) { incPWMOnTime(); } } checkLEDPWM(0, i); } int bottomOnValue = pwmOn; // *************** third pass - get on time maximum ************* setPWMOnTime(pwmOn + 50); for (int i = 0 ; i < 768 ; i++ ) { //loadNumberArray8s(); loadNumberArrayConfInt(pwmOn, 0); allBright(); outputDisplay(); if (getSmoothedHVSensorReading() > rawHVADCThreshold) { if ((i % 8) == 0 ) { decPWMOnTime(); } } checkLEDPWM(1, i); } int topOnValue = pwmOn; int aveOnValue = (bottomOnValue + topOnValue) / 2; setPWMOnTime(aveOnValue); // *************** fourth pass - adjust the frequency ************* rawHVADCThreshold = getRawHVADCThreshold(hvTargetVoltage + 5); // Calibrate HVGen at full for (int i = 0 ; i < 768 ; i++ ) { loadNumberArraySameValue(8); allBright(); outputDisplay(); checkHVVoltage(); checkLEDPWM(2, i); } } /** Set the PWM top time. Bounds check it so that it stays between the defined minimum and maximum, and that it does not go under the PWM On time (plus a safety margin). Set both the internal "pwmTop" value and the register. */ void setPWMTopTime(int newTopTime) { if (newTopTime < PWM_TOP_MIN) { newTopTime = PWM_TOP_MIN; } if (newTopTime > PWM_TOP_MAX) { newTopTime = PWM_TOP_MAX; } if (newTopTime < (pwmOn + PWM_OFF_MIN)) { newTopTime = pwmOn + PWM_OFF_MIN; } ICR1 = newTopTime; pwmTop = newTopTime; } /** Set the new PWM on time. Bounds check it to make sure that is stays between pulse min and max, and that it does not get bigger than PWM top, less the safety margin. Set both the internal "pwmOn" value and the register. */ void setPWMOnTime(int newOnTime) { if (newOnTime < PWM_PULSE_MIN) { newOnTime = PWM_PULSE_MIN; } if (newOnTime > PWM_PULSE_MAX) { newOnTime = PWM_PULSE_MAX; } if (newOnTime > (pwmTop - PWM_OFF_MIN)) { newOnTime = pwmTop - PWM_OFF_MIN; } OCR1A = newOnTime; pwmOn = newOnTime; } void incPWMOnTime() { setPWMOnTime(pwmOn + 1); } void decPWMOnTime() { setPWMOnTime(pwmOn - 1); } /** Get the HV sensor reading. Smooth it using a simple moving average calculation. */ int getSmoothedHVSensorReading() { int rawSensorVal = analogRead(sensorPin); double sensorDiff = rawSensorVal - sensorHVSmoothed; sensorHVSmoothed += (sensorDiff / sensorSmoothCountHV); int sensorHVSmoothedInt = (int) sensorHVSmoothed; return sensorHVSmoothedInt; } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_PIR_TIMEOUT) { byte pirTimeoutHi = Wire.read(); byte pirTimeoutLo = Wire.read(); pirTimeout = pirTimeoutHi*256 + pirTimeoutLo; EEPROM.write(EE_PIR_TIMEOUT_HI, pirTimeoutHi); EEPROM.write(EE_PIR_TIMEOUT_LO, pirTimeoutLo); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte minDimHi = Wire.read(); byte minDimLo = Wire.read(); minDim = minDimHi*256 + minDimLo; EEPROM.write(EE_MIN_DIM_HI, minDimHi); EEPROM.write(EE_MIN_DIM_LO, minDimLo); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_DP_ENABLE) { dpEnable = Wire.read(); EEPROM.write(EE_DP_ENABLE, dpEnable); } else if (operation == I2C_SHOW_VALUE) { // Three BCD values, plus time to show in seconds valueToShow[0] = Wire.read(); valueToShow[1] = Wire.read(); valueToShow[2] = Wire.read(); valueDisplayTime = Wire.read(); } else if (operation == I2C_SHOW_VALUE_FORMAT) { // Three BCD values, using the normal display type encoding in each nibble valueDisplayType[0] = Wire.read(); valueDisplayType[1] = Wire.read(); valueDisplayType[2] = Wire.read(); loadDisplayConfigValue(); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps; configArray[idx++] = backlightMode; configArray[idx++] = redCnl; configArray[idx++] = grnCnl; configArray[idx++] = bluCnl; configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = pirTimeout / 256; configArray[idx++] = pirTimeout % 256; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; configArray[idx++] = dpEnable; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } }
Авторское обновление программы – в основном добавлены адресные светодиоды на них бум. И еще инфракрасный датчик движения – включается при приближении. В динамике как я перевел на этот режим – более экономичное изделие. Я сравниваю с китайской платой так у этих 6 здоровенных ИН1 при засветке 900 циклов из 1000 и 50 раз в секунду яркость теряется ну совсем чуть а мощность потребления падает с ампера почти до 250 миллиампер от 12 вольт – один в один так же только там малюсенькие ин16 . Зеленая технология – в русском языке это конечно смысл что совсем не доделаная, а с экономией энергии у нас не заморачиваются. Пока – работает то от батареи а это плюс – в 4 раза дольше время работы и вместо 6 комплектов батарей надо 2. как сравниваются 2 файла программы если там небольшие изменения, ну да наверно удобнее github . но можно и на компе просто – используя total commander там есть команда Сравнить по содержимому compare by content. А в линухе – на убунте конечно лучше как самой продвинутой системе – ставится midnight commander а если хочется в графике то есть програмка meld . вот и патч сделаный в ней
--- smb://qwerty1/g$/root/in14clock/FirmwareV1.ino +++ /run/user/1000/gvfs/smb-share:server=qwerty1,share=g$/meld-test2 gnome3 ubuntu freebsd use smb2 - no problem (2021) @@ -1,7 +1,7 @@ //********************************************************************************** //* Main code for an Arduino based Nixie clock. Features: * +//* - WiFi Clock interface for the WiFiModule OR * //* - Real Time Clock interface for DS3231 * -//* - WiFi Clock interface for the WiFiModule * //* - Digit fading with configurable fade length * //* - Digit scrollback with configurable scroll speed * //* - Configuration stored in EEPROM * @@ -9,7 +9,8 @@ //* - Single button operation with software debounce * //* - Single K155ID1 for digit display (other versions use 2 or even 6!) * //* - Automatic dimming, using a Light Dependent Resistor * -//* - RGB back light management * +//* - RGB back light management using individually addressable WS2812B * +//* - PIR sensor to turn off display when no one is around * //* * //* nixie@protonmail.ch * //* * @@ -25,12 +26,15 @@ // using the ZIP files in the "libraries" directory #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) #include <TimeLib.h> // http://playground.arduino.cc/code/time (Margolis 1.5.0) +#include <Adafruit_NeoPixel.h> // https://github.com/adafruit/Adafruit_NeoPixel (Adafruit 1.1.8) // Other parts of the code, broken out for clarity #include "ClockButton.h" #include "Transition.h" #include "DisplayDefs.h" #include "I2CDefs.h" + +#define FWV2 // "REV3" for Modular Rev3 "FWV2" for ClassicRev6 and ModularRev3.01 //********************************************************************************** //********************************************************************************** @@ -73,9 +77,18 @@ #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again +#define EE_PIR_TIMEOUT_LO 37 // The PIR timeout time in S, low byte +#define EE_PIR_TIMEOUT_HI 38 // The PIR timeout time in S, high byte +#define EE_PIR_PULLUP 39 // If we use the internal pullup on the PIR pin (false = use 3V3 PIR, PIR connected, true = no PIR connected or 5V PIR) +#define EE_MIN_DIM_LO 40 // The minimum dimming value, low byte +#define EE_MIN_DIM_HI 41 // The minimum dimming value, high byte +#define EE_DP_ENABLE 42 // Control the decimal points // Software version shown in config menu -#define SOFTWARE_VERSION 57 +#define SOFTWARE_VERSION 358 + +// how often we make reference to the external time provider +#define READ_TIME_PROVIDER_MILLIS 60000 // Update the internal time provider from the external source once every minute // Display handling #define DIGIT_DISPLAY_COUNT 1000 // The number of times to traverse inner fade loop per digit @@ -160,12 +173,14 @@ #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // -#define MODE_HR_BLNK_START 13 // -#define MODE_HR_BLNK_END 14 // +#define MODE_HR_BLNK_START 13 // skipped if not using hour blanking +#define MODE_HR_BLNK_END 14 // skipped if not using hour blanking #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true + #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true + #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH @@ -174,37 +189,51 @@ #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // + #define MODE_SLOTS_MODE 22 // +// PIR +#define MODE_PIR_TIMEOUT_UP 23 // +#define MODE_PIR_TIMEOUT_DOWN 24 // + // Back light -#define MODE_BACKLIGHT_MODE 23 // -#define MODE_RED_CNL 24 // -#define MODE_GRN_CNL 25 // -#define MODE_BLU_CNL 26 // -#define MODE_CYCLE_SPEED 27 // speed the colour cycle cyles at - -// HV generation -#define MODE_TARGET_HV_UP 28 // -#define MODE_TARGET_HV_DOWN 29 // -#define MODE_PULSE_UP 30 // -#define MODE_PULSE_DOWN 31 // - -#define MODE_MIN_DIM_UP 32 // -#define MODE_MIN_DIM_DOWN 33 // - -#define MODE_ANTI_GHOST_UP 34 // -#define MODE_ANTI_GHOST_DOWN 35 // +#define MODE_BACKLIGHT_MODE 25 // +#define MODE_RED_CNL 26 // +#define MODE_GRN_CNL 27 // +#define MODE_BLU_CNL 28 // +#define MODE_CYCLE_SPEED 29 // + +// HV generation - Not Available over I2C +#define MODE_TARGET_HV_UP 30 // +#define MODE_TARGET_HV_DOWN 31 // + +#define MODE_PULSE_UP 32 // +#define MODE_PULSE_DOWN 33 // + +// Minimum dimming value for old tubes +#define MODE_MIN_DIM_UP 34 // +#define MODE_MIN_DIM_DOWN 35 // + +// Anti-ghosting for old tubes - Not Available over I2C +#define MODE_ANTI_GHOST_UP 36 // +#define MODE_ANTI_GHOST_DOWN 37 // + +// Use the PIR pin pullup resistor - Not Available over I2C +#define MODE_USE_PIR_PULLUP 38 // 1 = use Pullup +#define USE_PIR_PULLUP_DEFAULT true + +#define MODE_ENABLE_DP 39 // Set the decimal points // Temperature -#define MODE_TEMP 36 // +#define MODE_TEMP 40 // Show the temperature // Software Version -#define MODE_VERSION 37 // +#define MODE_VERSION 41 // // Tube test - all six digits, so no flashing mode indicator -#define MODE_TUBE_TEST 38 - -#define MODE_MAX 38 +#define MODE_TUBE_TEST 42 + +#define MODE_MAX 42 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press @@ -244,8 +273,9 @@ #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs -#define BLANK_MODE_MAX 2 -#define BLANK_MODE_DEFAULT 2 +#define BLANK_MODE_ALL 3 // Use blanking for tubes, LEDs and separators +#define BLANK_MODE_MAX BLANK_MODE_BOTH +#define BLANK_MODE_DEFAULT BLANK_MODE_ALL #define BACKLIGHT_MIN 0 #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it @@ -254,8 +284,10 @@ #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming -#define BACKLIGHT_MAX 5 -#define BACKLIGHT_DEFAULT 0 +#define BACKLIGHT_COLOUR_TIME 6 // use "ColourTime" - different colours for each digit value +#define BACKLIGHT_COLOUR_TIME_DIM 7 // use "ColourTime" - dims with bulb dimming +#define BACKLIGHT_MAX 7 +#define BACKLIGHT_DEFAULT 4 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 @@ -264,6 +296,10 @@ #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 + +#define PIR_TIMEOUT_MIN 60 // 1 minute in seconds +#define PIR_TIMEOUT_MAX 3600 // 1 hour in seconds +#define PIR_TIMEOUT_DEFAULT 300 // 5 minutes in seconds #define TEMP_DISPLAY_MODE_DUR_MS 5000 @@ -278,13 +314,20 @@ #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 +#define DP_ENABLE_MIN 0 +#define DP_ENABLE_ALL 0 // Use all DPs +#define DP_ENABLE_AMPM 1 // Use only he AM/PM indicator (no PIR) +#define DP_ENABLE_NONE 2 // Use no DPs - all off +#define DP_ENABLE_MAX DP_ENABLE_NONE +#define DP_ENABLE_DEFAULT DP_ENABLE_AMPM + // RTC address #define RTC_I2C_ADDRESS 0x68 #define MAX_WIFI_TIME 5 -#define DO_NOT_APPLY_LEAD_0_BLANK false -#define APPLY_LEAD_0_BLANK true +#define DO_NOT_APPLY_LEAD_0_BLANK false +#define APPLY_LEAD_0_BLANK true //********************************************************************************** //********************************************************************************** @@ -302,15 +345,26 @@ #define ledPin_0_d 12 // package pin 18 // PB4 // anode pins +#ifdef REV3 + #define ledPin_a_1 A3 // high - Hours tens // Package pin 26 // PC3 // Analog or digital input for PIR +#else + #define ledPin_a_1 7 // high - Hours tens // package pin 13 // PD7 +#endif +#define ledPin_a_2 4 // - Hours units // package pin 6 // PD4 +#define ledPin_a_3 3 // - Mins tens // package pin 5 // PD3 +#define ledPin_a_4 2 // - Mins units // package pin 4 // PD2 +#define ledPin_a_5 1 // - Secs tens // package pin 3 // PD1 #define ledPin_a_6 0 // low - Secs units // package pin 2 // PD0 -#define ledPin_a_5 1 // - Secs tens // package pin 3 // PD1 -#define ledPin_a_4 2 // - Mins units // package pin 4 // PD2 -#define ledPin_a_3 4 // - Mins tens // package pin 6 // PD4 -#define ledPin_a_2 A2 // - Hours units // package pin 25 // PC2 -#define ledPin_a_1 A3 // high - Hours tens // package pin 26 // PC3 // button input -#define inputPin1 7 // package pin 13 // PD7 +#define inputPin1 A2 // Package pin 25 // PC2 // Analog or digital input for button. + +// PIR input +#ifdef REV3 + #define pirPin 7 // package pin 13 // PD7 +#else + #define pirPin A3 // Package pin 26 // PC3 // Analog or digital input for PIR +#endif // PWM pin used to drive the DC-DC converter #define hvDriverPin 9 // package pin 15 // PB1 @@ -318,16 +372,16 @@ // Tick led - PWM capable #define tickLed 11 // package pin 17 // PB3 -// PWM capable output for backlight -#define RLed 6 // package pin 12 // PD6 -#define GLed 5 // package pin 11 // PD5 -#define BLed 3 // package pin 5 // PD3 +// Decimal point - PWM capable +#define DP 5 // package pin 11 // PD5 + +// PWM capable output for backlight - Neo Pixel chain +#define LED_DOUT 6 // package pin 12 // PD6 #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** - Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* @@ -335,21 +389,15 @@ int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; -// All-In-One Rev1 has a mix up in the tube wiring. All other clocks are -// correct. -#define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] - // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler -#ifdef AIO_REV1 - // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. - byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; -#else - byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; -#endif +byte decodeDigit[16] = {2, 3, 7, 6, 4, 5, 1, 0, 9, 8, 10, 10, 10, 10, 10, 10}; + +// Settings for ZM1000 +// byte decodeDigit[16] = {6, 9, 8, 2, 0, 1, 5, 4, 3, 7, 10, 10, 10, 10, 10, 10}; // Driver pins for the anodes -byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; +byte anodePins[DIGIT_COUNT] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on @@ -359,11 +407,17 @@ double sensorHVSmoothed = 0; // ************************ Display management ************************ -byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; -byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; -byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; -byte fadeState[6] = {0, 0, 0, 0, 0, 0}; -byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached +byte NumberArray[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; +byte currNumberArray[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; +byte displayType[DIGIT_COUNT] = {FADE, FADE, FADE, FADE, FADE, FADE}; +byte fadeState[DIGIT_COUNT] = {0, 0, 0, 0, 0, 0}; +byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module +byte valueDisplayTime = 0; +byte valueToShow[3] = {0, 0, 0}; +byte valueDisplayType[3] = {0x33, 0x33, 0x33}; // All normal by default + +// Decimal point indicators +boolean dpArray[DIGIT_COUNT] = {false, false, false, false, false, false}; // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second @@ -402,6 +456,8 @@ byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; +boolean blankSeparators = false; +byte dpEnable = DP_ENABLE_DEFAULT; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; @@ -411,6 +467,7 @@ int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; +boolean usePIRPullup = true; // ************************ Clock variables ************************ // RTC, uses Analogue pins A4 (SDA) and A5 (SCL) @@ -428,6 +485,11 @@ unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; + +// PIR +unsigned long pirTimeout = PIR_TIMEOUT_DEFAULT; +unsigned long pirLastSeen = 0; + boolean triggeredThisSec = false; byte useRTC = false; // true if we detect an RTC @@ -449,8 +511,17 @@ byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; -// Back light cycling int colors[3]; + +// individual channel colours for the LEDs +byte ledR[DIGIT_COUNT]; +byte ledG[DIGIT_COUNT]; +byte ledB[DIGIT_COUNT]; + +// set up the NeoPixel library +Adafruit_NeoPixel leds = Adafruit_NeoPixel(6, LED_DOUT, NEO_GRB + NEO_KHZ800); + +// Strategy 3 int changeSteps = 0; byte currentColour = 0; @@ -488,15 +559,13 @@ pinMode(ledPin_a_6, OUTPUT); pinMode(tickLed, OUTPUT); - pinMode(RLed, OUTPUT); - pinMode(GLed, OUTPUT); - pinMode(BLed, OUTPUT); + pinMode(LED_DOUT, OUTPUT); + pinMode(DP, OUTPUT); + pinMode(pirPin, INPUT); // The LEDS sometimes glow at startup, it annoys me, so turn them completely off analogWrite(tickLed, 0); - analogWrite(RLed, 0); - analogWrite(GLed, 0); - analogWrite(BLed, 0); + setAllLEDs(0,0,0); // NOTE: // Grounding the input pin causes it to actuate @@ -524,10 +593,6 @@ tccrOn = TCCR1A; - // Set up timer 2 like timer 0 (for RGB leds) - TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); - TCCR2B = (1 << CS22); - // we don't need the HV yet, so turn it off TCCR1A = tccrOff; @@ -535,6 +600,9 @@ sei(); // ********************************************************************** + + // Set up the LED output + leds.begin(); // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); @@ -583,6 +651,9 @@ // Read EEPROM values readEEPROMValues(); + // Not setting the pullup resistor allows us to use 3V3 devices (e.g. RCWL-0516) + digitalWrite(pirPin, usePIRPullup); // set pull up resistor - if no PIR connected, default to "triggered" + // set our PWM profile setPWMOnTime(pwmOn); setPWMTopTime(pwmTop); @@ -605,6 +676,9 @@ // turn off Scrollback scrollback = false; + + // set backlights to change with the displayed digits + backlightMode = BACKLIGHT_COLOUR_TIME; // All the digits on full allBright(); @@ -632,12 +706,10 @@ outputDisplay(); checkHVVoltage(); - setLedsTestPattern(nowMillis); + setLeds(); button1.checkButton(nowMillis); - if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; - blankTubes = false; } } @@ -646,7 +718,7 @@ } // reset the LEDs - setLedsTestPattern(0); + setLeds(); // Set up the HVG if we need to if (EEPROM.read(EE_HVG_NEED_CALIB)) { @@ -670,7 +742,7 @@ // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); - setTime(12, 34, 56, 1, 3, 2017); + setTime(12, 34, 56, 1, 3, 2019); getRTCTime(); // Show the version for 1 s @@ -693,6 +765,7 @@ //* Main loop * //********************************************************************************** //********************************************************************************** +boolean millisNotSet = true; void loop() { nowMillis = millis(); @@ -708,10 +781,10 @@ if (hour() == 0) { performOncePerDayProcessing(); } - + performOncePerHourProcessing(); } - + performOncePerMinuteProcessing(); } @@ -719,7 +792,7 @@ // Make sure we don't call multiple times triggeredThisSec = true; - + if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } @@ -830,8 +903,6 @@ digitOn(digitBurnDigit, digitBurnValue); } - // ------------------------------------------------------------------------------- - // Prepare the tick and backlight LEDs setLeds(); } @@ -869,10 +940,11 @@ // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { + boolean pirBlanked = checkPIR(nowMillis); boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode - blanked = nativeBlanked && (blankSuppressedMillis == 0); + blanked = (nativeBlanked || pirBlanked) && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { @@ -883,6 +955,12 @@ blanked = false; } setTubesAndLEDSBlankMode(); + + // Decrement the value display counter + // 0xff means "forever", so don't decrement it + if ((valueDisplayTime > 0) && (valueDisplayTime < 0xff)) { + valueDisplayTime--; + } // Slow regulation of the voltage checkHVVoltage(); @@ -905,6 +983,13 @@ // get the time from the external RTC provider - (if installed) getRTCTime(); } + + // AM/PM indicator - show if we are in 12H mode and it is PM + if ((dpEnable == DP_ENABLE_ALL) || (dpEnable == DP_ENABLE_AMPM)) { + dpArray[1] = hourMode && (hour() > 12); + } else { + dpArray[1] = false; + } } // ************************************************************ @@ -939,44 +1024,60 @@ analogWrite(tickLed, getLEDAdjusted(255, pwmFactor, dimFactor)); if (blankLEDs) { - analogWrite(RLed, 0); - analogWrite(GLed, 0); - analogWrite(BLed, 0); + setAllLEDs( getLEDAdjusted(0, 1, 1), + getLEDAdjusted(0, 1, 1), + getLEDAdjusted(0, 1, 1)); } else { // RGB Backlight PWM led output if (currentMode == MODE_TIME) { switch (backlightMode) { case BACKLIGHT_FIXED: - analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], 1, 1)); - analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, 1)); - analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, 1)); + setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], 1, 1), + getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, 1), + getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, 1)); break; case BACKLIGHT_PULSE: - analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, 1)); - analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, 1)); - analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, 1)); + setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, 1), + getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, 1), + getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, 1)); break; case BACKLIGHT_CYCLE: cycleColours3(colors); - analogWrite(RLed, getLEDAdjusted(colors[0], 1, 1)); - analogWrite(GLed, getLEDAdjusted(colors[1], 1, 1)); - analogWrite(BLed, getLEDAdjusted(colors[2], 1, 1)); + setAllLEDs( getLEDAdjusted(colors[0], 1, 1), + getLEDAdjusted(colors[1], 1, 1), + getLEDAdjusted(colors[2], 1, 1)); break; case BACKLIGHT_FIXED_DIM: - analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], 1, dimFactor)); - analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, dimFactor)); - analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, dimFactor)); + setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], 1, dimFactor), + getLEDAdjusted(rgb_backlight_curve[grnCnl], 1, dimFactor), + getLEDAdjusted(rgb_backlight_curve[bluCnl], 1, dimFactor)); break; case BACKLIGHT_PULSE_DIM: - analogWrite(RLed, getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, dimFactor)); - analogWrite(GLed, getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, dimFactor)); - analogWrite(BLed, getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, dimFactor)); + setAllLEDs( getLEDAdjusted(rgb_backlight_curve[redCnl], pwmFactor, dimFactor), + getLEDAdjusted(rgb_backlight_curve[grnCnl], pwmFactor, dimFactor), + getLEDAdjusted(rgb_backlight_curve[bluCnl], pwmFactor, dimFactor)); break; case BACKLIGHT_CYCLE_DIM: cycleColours3(colors); - analogWrite(RLed, getLEDAdjusted(colors[0], 1, dimFactor)); - analogWrite(GLed, getLEDAdjusted(colors[1], 1, dimFactor)); - analogWrite(BLed, getLEDAdjusted(colors[2], 1, dimFactor)); + setAllLEDs( getLEDAdjusted(colors[0], 1, dimFactor), + getLEDAdjusted(colors[1], 1, dimFactor), + getLEDAdjusted(colors[2], 1, dimFactor)); + break; + case BACKLIGHT_COLOUR_TIME: + for (int i = 0 ; i < 6 ; i++) { + ledR[5-i] = getLEDAdjusted(colourTimeR[NumberArray[i]],1,1); + ledG[5-i] = getLEDAdjusted(colourTimeG[NumberArray[i]],1,1); + ledB[5-i] = getLEDAdjusted(colourTimeB[NumberArray[i]],1,1); + } + outputLEDBuffer(); + break; + case BACKLIGHT_COLOUR_TIME_DIM: + for (int i = 0 ; i < 6 ; i++) { + ledR[5-i] = getLEDAdjusted(colourTimeR[NumberArray[i]],1,dimFactor); + ledG[5-i] = getLEDAdjusted(colourTimeG[NumberArray[i]],1,dimFactor); + ledB[5-i] = getLEDAdjusted(colourTimeB[NumberArray[i]],1,dimFactor); + } + outputLEDBuffer(); break; } } else { @@ -994,17 +1095,63 @@ if ((ledBlinkNumber <= nextMode) && (ledBlinkNumber > 0)) { if (ledBlinkCtr < 3) { - analogWrite(RLed, 255); - analogWrite(GLed, 255); - analogWrite(BLed, 255); + setAllLEDs(255,255,255); } else { - analogWrite(RLed, 0); - analogWrite(GLed, 0); - analogWrite(BLed, 0); + setAllLEDs(0,0,0); } } } } +} + +// ************************************************************ +// Check the PIR status. If we don't have a PIR installed, we +// don't want to respect the pin value, because it would defeat +// normal day blanking. The first time the PIR takes the pin low +// we mark that we have a PIR and we should start to respect +// the sensor. +// Returns true if PIR sensor is installed and we are blanked +// ************************************************************ +boolean checkPIR(unsigned long nowMillis) { + boolean pirvalue = (digitalRead(pirPin) == HIGH); + + boolean useDPs = (dpEnable == DP_ENABLE_ALL); + dpArray[5] = pirvalue && useDPs; + + if (pirvalue) { + pirLastSeen = nowMillis; + return false; + } else { + if (nowMillis > (pirLastSeen + (pirTimeout * 1000))) { + dpArray[4] = false; + return true; + } else { + dpArray[4] = true && useDPs; + return false; + } + } +} + +// ************************************************************ +// Set back light LEDs to the same colour +// ************************************************************ +void setAllLEDs(byte red, byte green, byte blue) { + for (int i = 0 ; i < DIGIT_COUNT ; i++) { + ledR[i] = red; + ledG[i] = green; + ledB[i] = blue; + } + outputLEDBuffer(); +} + +// ************************************************************ +// Put the led buffers out +// ************************************************************ +void outputLEDBuffer() { + for (int i = 0 ; i < DIGIT_COUNT ; i++) { + leds.setPixelColor(i, leds.Color(ledR[i], ledG[i], ledB[i])); + } + leds.show(); } // ************************************************************ @@ -1129,6 +1276,12 @@ displayConfig(); break; } + case MODE_PIR_TIMEOUT_UP: + case MODE_PIR_TIMEOUT_DOWN: { + loadNumberArrayConfInt(pirTimeout, displayMode); + displayConfig(); + break; + } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); @@ -1188,6 +1341,16 @@ case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); + displayConfig(); + break; + } + case MODE_USE_PIR_PULLUP: { + loadNumberArrayConfBool(usePIRPullup, displayMode); + displayConfig(); + break; + } + case MODE_ENABLE_DP: { + loadNumberArrayConfInt(dpEnable, displayMode); displayConfig(); break; } @@ -1525,6 +1688,17 @@ fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } + case MODE_DISPLAY_SCROLL_STEPS_UP: { + if (button1.isButtonPressedAndReleased()) { + scrollSteps++; + if (scrollSteps > SCROLL_STEPS_MAX) { + scrollSteps = SCROLL_STEPS_MIN; + } + } + loadNumberArrayConfInt(scrollSteps, displayMode); + displayConfig(); + break; + } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; @@ -1536,14 +1710,25 @@ displayConfig(); break; } - case MODE_DISPLAY_SCROLL_STEPS_UP: { - if (button1.isButtonPressedAndReleased()) { - scrollSteps++; - if (scrollSteps > SCROLL_STEPS_MAX) { - scrollSteps = SCROLL_STEPS_MIN; - } - } - loadNumberArrayConfInt(scrollSteps, displayMode); + case MODE_PIR_TIMEOUT_UP: { + if (button1.isButtonPressedAndReleased()) { + pirTimeout+=10; + if (pirTimeout > PIR_TIMEOUT_MAX) { + pirTimeout = PIR_TIMEOUT_MIN; + } + } + loadNumberArrayConfInt(pirTimeout, displayMode); + displayConfig(); + break; + } + case MODE_PIR_TIMEOUT_DOWN: { + if (button1.isButtonPressedAndReleased()) { + pirTimeout-=10; + if (pirTimeout < PIR_TIMEOUT_MIN) { + pirTimeout = PIR_TIMEOUT_MAX; + } + } + loadNumberArrayConfInt(pirTimeout, displayMode); displayConfig(); break; } @@ -1704,6 +1889,26 @@ dispCount = DIGIT_DISPLAY_COUNT + antiGhost; } loadNumberArrayConfInt(antiGhost, displayMode); + displayConfig(); + break; + } + case MODE_USE_PIR_PULLUP: { + if (button1.isButtonPressedAndReleased()) { + usePIRPullup = !usePIRPullup; + } + loadNumberArrayConfBool(usePIRPullup, displayMode); + digitalWrite(pirPin, usePIRPullup); + displayConfig(); + break; + } + case MODE_ENABLE_DP: { + if (button1.isButtonPressedAndReleased()) { + dpEnable++; + if (dpEnable > DP_ENABLE_MAX) { + dpEnable = DP_ENABLE_MIN; + } + } + loadNumberArrayConfInt(dpEnable, displayMode); displayConfig(); break; } @@ -1831,6 +2036,18 @@ NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } +} + +// ************************************************************ +// Show the value we got over I2C +// ************************************************************ +void loadNumberArrayValue() { + NumberArray[5] = valueToShow[2] & 0xf; + NumberArray[4] = valueToShow[2] >> 4; + NumberArray[3] = valueToShow[1] & 0xf; + NumberArray[2] = valueToShow[1] >> 4; + NumberArray[1] = valueToShow[0] & 0xf; + NumberArray[0] = valueToShow[0] >> 4; } // ************************************************************ @@ -2024,6 +2241,8 @@ for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { + digitalWrite(DP, dpArray[i]); + if (blankTubes) { tmpDispType = BLANKED; } else { @@ -2082,7 +2301,10 @@ tmpDispType = SCROLL; } - // manage scrolling, count the digits down + // manage fading, each impression we show 1 fade step less of the old + // digit and 1 fade step more of the new + // manage fading, each impression we show 1 fade step less of the old + // digit and 1 fade step more of the new if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { @@ -2100,8 +2322,6 @@ fadeState[i] = fadeState[i] - 1; } } - // manage fading, each impression we show 1 fade step less of the old - // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { @@ -2156,9 +2376,13 @@ // ************************************************************ void digitOn(int digit, int value) { switch (digit) { +#ifdef REV3 case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); - case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); - case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); +#else + case 0: PORTD = PORTD | B10000000; break; // PD7 - equivalent to digitalWrite(ledPin_a_1,HIGH); +#endif + case 1: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_2,HIGH); + case 2: PORTD = PORTD | B00001000; break; // PD3 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); @@ -2169,15 +2393,18 @@ } // ************************************************************ -// Finish displaying a digit and turn the HVGen on +// Finish displaying a digit and turn the HVGen off // ************************************************************ void digitOff() { TCCR1A = tccrOff; - //digitalWrite(anodePins[digit], LOW); // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster - PORTC = PORTC & B11110011; - PORTD = PORTD & B11101000; +#ifdef REV3 + PORTC = PORTC & B11110111; + PORTD = PORTD & B11100000; +#else + PORTD = PORTD & B01100000; +#endif } // ************************************************************ @@ -2381,6 +2608,18 @@ if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; +} + +// ************************************************************ +// Display preset +// ************************************************************ +void loadDisplayConfigValue() { + displayType[5] = valueDisplayType[2] & 0xf; + displayType[4] = valueDisplayType[2] >> 4; + displayType[5] = valueDisplayType[1] & 0xf; + displayType[2] = valueDisplayType[1] >> 4; + displayType[1] = valueDisplayType[0] & 0xf; + displayType[0] = valueDisplayType[0] >> 4; } // ************************************************************ @@ -2554,18 +2793,28 @@ { blankTubes = true; blankLEDs = false; + blankSeparators = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; + blankSeparators = false; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; + blankSeparators = false; + break; + } + case BLANK_MODE_ALL: + { + blankTubes = true; + blankLEDs = true; + blankSeparators = true; break; } } @@ -2575,54 +2824,21 @@ } } -// ************************************************************ -// Show a random RGB colour: used to indicate a factory reset -// ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { - digitalWrite(RLed, HIGH); + setAllLEDs(255,0,0); } if (random(3) == 0) { - digitalWrite(GLed, HIGH); + setAllLEDs(0,255,0); } if (random(3) == 0) { - digitalWrite(BLed, HIGH); + setAllLEDs(0,0,255); } delay(delayVal); digitalWrite(tickLed, LOW); - digitalWrite(RLed, LOW); - digitalWrite(GLed, LOW); - digitalWrite(BLed, LOW); + setAllLEDs(0,0,0); delay(delayVal); -} - -// ************************************************************ -// Used to set the LEDs during test mode -// ************************************************************ -void setLedsTestPattern(unsigned long currentMillis) { - unsigned long currentSec = currentMillis / 1000; - byte phase = currentSec % 4; - digitalWrite(tickLed, LOW); - digitalWrite(RLed, LOW); - digitalWrite(GLed, LOW); - digitalWrite(BLed, LOW); - - if (phase == 0) { - digitalWrite(tickLed, HIGH); - } - - if (phase == 1) { - digitalWrite(RLed, HIGH); - } - - if (phase == 2) { - digitalWrite(GLed, HIGH); - } - - if (phase == 3) { - digitalWrite(BLed, HIGH); - } } // ************************************************************ @@ -2757,9 +2973,13 @@ EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); + EEPROM.write(EE_PIR_TIMEOUT_LO, pirTimeout % 256); + EEPROM.write(EE_PIR_TIMEOUT_HI, pirTimeout / 256); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); + EEPROM.write(EE_PIR_PULLUP, usePIRPullup); + EEPROM.write(EE_DP_ENABLE, dpEnable); } // ************************************************************ @@ -2876,6 +3096,16 @@ } dispCount = DIGIT_DISPLAY_COUNT + antiGhost; + pirTimeout = EEPROM.read(EE_PIR_TIMEOUT_HI) * 256 + EEPROM.read(EE_PIR_TIMEOUT_LO); + if ((pirTimeout < PIR_TIMEOUT_MIN) || (pirTimeout > PIR_TIMEOUT_MAX)) { + pirTimeout = PIR_TIMEOUT_DEFAULT; + } + + minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); + if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { + minDim = MIN_DIM_DEFAULT; + } + blankMode= EEPROM.read(EE_BLANK_MODE); if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; @@ -2886,6 +3116,13 @@ slotsMode= EEPROM.read(EE_SLOTS_MODE); if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; + } + + usePIRPullup = EEPROM.read(EE_PIR_PULLUP); + + dpEnable = EEPROM.read(EE_DP_ENABLE); + if ((dpEnable < DP_ENABLE_MIN) || (dpEnable > DP_ENABLE_MAX)) { + dpEnable = DP_ENABLE_DEFAULT; } } @@ -2920,9 +3157,12 @@ pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; antiGhost = ANTI_GHOST_DEFAULT; + pirTimeout = PIR_TIMEOUT_DEFAULT; useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; + usePIRPullup = USE_PIR_PULLUP_DEFAULT; + dpEnable = DP_ENABLE_DEFAULT; saveEEPROMValues(); } @@ -3009,21 +3249,69 @@ } // ****************************************************************** -// Routine to check the PWM LEDs +// Routine to set the LEDs +// LEDPin // brightens and dims a PWM capable LED // - 0 to 255 ramp up // - 256 to 511 plateau // - 512 to 767 ramp down // ****************************************************************** void checkLEDPWM(byte LEDPin, int step) { + if (step > 767) { - analogWrite(LEDPin, getLEDAdjusted(0, 1, 1)); + if (LEDPin == tickLed) { + analogWrite(LEDPin, getLEDAdjusted(0, 1, 1)); + } else { + setAllLEDs(0,0,0); + } } else if (step > 512) { - analogWrite(LEDPin, getLEDAdjusted(255 - (step - 512), 1, 1)); + if (LEDPin == tickLed) { + analogWrite(LEDPin, getLEDAdjusted(255 - (step - 512), 1, 1)); + } else { + switch (LEDPin) { + case 0: + setAllLEDs(getLEDAdjusted(255 - (step - 512),1,1),0,0); + break; + case 1: + setAllLEDs(0,getLEDAdjusted(255 - (step - 512),1,1),0); + break; + case 2: + setAllLEDs(0,0,getLEDAdjusted(255 - (step - 512),1,1)); + break; + } + } } else if (step > 255) { - analogWrite(LEDPin, getLEDAdjusted(255, 1, 1)); + if (LEDPin == tickLed) { + analogWrite(LEDPin, getLEDAdjusted(255, 1, 1)); + } else { + switch (LEDPin) { + case 0: + setAllLEDs(getLEDAdjusted(255,1,1),0,0); + break; + case 1: + setAllLEDs(0,getLEDAdjusted(255,1,1),0); + break; + case 2: + setAllLEDs(0,0,getLEDAdjusted(255,1,1)); + break; + } + } } else if (step > 0) { - analogWrite(LEDPin, getLEDAdjusted(step, 1, 1)); + if (LEDPin == tickLed) { + analogWrite(LEDPin, getLEDAdjusted(step, 1, 1)); + } else { + switch (LEDPin) { + case 0: + setAllLEDs(getLEDAdjusted(step,1,1),0,0); + break; + case 1: + setAllLEDs(0,getLEDAdjusted(step,1,1),0); + break; + case 2: + setAllLEDs(0,0,getLEDAdjusted(step,1,1)); + break; + } + } } } @@ -3078,7 +3366,7 @@ incPWMOnTime(); } } - checkLEDPWM(RLed, i); + checkLEDPWM(0, i); } int bottomOnValue = pwmOn; @@ -3096,7 +3384,7 @@ decPWMOnTime(); } } - checkLEDPWM(GLed, i); + checkLEDPWM(1, i); } int topOnValue = pwmOn; @@ -3113,7 +3401,7 @@ allBright(); outputDisplay(); checkHVVoltage(); - checkLEDPWM(BLed, i); + checkLEDPWM(2, i); } } @@ -3265,6 +3553,18 @@ ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); + } else if (operation == I2C_SET_OPTION_PIR_TIMEOUT) { + byte pirTimeoutHi = Wire.read(); + byte pirTimeoutLo = Wire.read(); + pirTimeout = pirTimeoutHi*256 + pirTimeoutLo; + EEPROM.write(EE_PIR_TIMEOUT_HI, pirTimeoutHi); + EEPROM.write(EE_PIR_TIMEOUT_LO, pirTimeoutLo); + } else if (operation == I2C_SET_OPTION_MIN_DIM) { + byte minDimHi = Wire.read(); + byte minDimLo = Wire.read(); + minDim = minDimHi*256 + minDimLo; + EEPROM.write(EE_MIN_DIM_HI, minDimHi); + EEPROM.write(EE_MIN_DIM_LO, minDimLo); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); @@ -3278,12 +3578,21 @@ } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); - } else if (operation == I2C_SET_OPTION_MIN_DIM) { - byte dimHI = Wire.read(); - byte dimLO = Wire.read(); - minDim = dimHI * 256 + dimLO; - EEPROM.write(EE_MIN_DIM_HI, dimHI); - EEPROM.write(EE_MIN_DIM_LO, dimLO); + } else if (operation == I2C_SET_OPTION_DP_ENABLE) { + dpEnable = Wire.read(); + EEPROM.write(EE_DP_ENABLE, dpEnable); + } else if (operation == I2C_SHOW_VALUE) { + // Three BCD values, plus time to show in seconds + valueToShow[0] = Wire.read(); + valueToShow[1] = Wire.read(); + valueToShow[2] = Wire.read(); + valueDisplayTime = Wire.read(); + } else if (operation == I2C_SHOW_VALUE_FORMAT) { + // Three BCD values, using the normal display type encoding in each nibble + valueDisplayType[0] = Wire.read(); + valueDisplayType[1] = Wire.read(); + valueDisplayType[2] = Wire.read(); + loadDisplayConfigValue(); } } @@ -3313,8 +3622,11 @@ configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; + configArray[idx++] = pirTimeout / 256; + configArray[idx++] = pirTimeout % 256; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; + configArray[idx++] = dpEnable; Wire.write(configArray, I2C_DATA_SIZE); }
а вот это прошивка я уверен что все прочитали из 100 заходов двое. шпиенская система подсказыает. и вот этот один покупал в Митино детальки, наверно делает часы а второй скорее всего я. вот прошивка с небольшими доделками. Применение – загрузить ардуино лучше из вложений, добавить библиотеки – как бы написано где но лучше взять посмотреть в программе менеджер библиотек. Выбрать конструкцию – оригинальную или здешнюю которая в 2 раза сложнее. Выбрать нужную прошивку- открыть скетч в ардуино, дополнительные файлы переписать в каталог библиотек сделав там папку. они вроде как не менялись. Если ардуинка с загрузчиком то сразу запустится все. А если не очень – все вопросы есть на сайте ардуино. Выбрать .. вот часы показывают 01 01 01 эт баиньки пора.
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // 500 //1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // 499 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 400 // Minimum value we can set to #define MIN_DIM_DEFAULT 120 // The default minimum dim count #define MIN_DIM_MIN 10 // The minimum dim count #define MIN_DIM_MAX 350 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 60 //100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 450 //700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second //50 is 1 sec #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value //const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; //200 int DIM_VALUE = 25; //200 is too bright int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = true; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT_PULLUP ); // set the input pin 1 // add resistor // вернул настройку HV и сброс до заводских настроек (нажать кнопку при включении) /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // Set up timer 2 like timer 0 (for RGB leds) TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); TCCR2B = (1 << CS22); // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset /* for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } */ // mark that we need the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера // setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } if (doTestPattern) { boolean oldUseLDR = useLDR; // byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); // checkHVVoltage(); // setLedsTestPattern(nowMillis); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; blankTubes = false; } } useLDR = oldUseLDR; // backlightMode = oldBacklightMode; } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); // setTime(12, 34, 56, 1, 3, 2017); // getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { if (debug){ Serial.println(" butt 2s "); } // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { if (debug){ Serial.println(" button 1s p-r "); } currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); // 120 dark (night) 999 bright - day fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 0; // 0 - не дергаю однорукого бандита acp off } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 7) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter but useless - current set as normal light OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (second() == 15) { // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; // no ldr but useLDR true (test) //sensorSmoothedResult = dimDark +1; sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage //checkHVVoltage(); // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) one time each minute if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); /* nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.setAll(HIGH); // off all tubes shifter.write(); //send changes to the chain and display them */ } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now (OK) // 46 impression per sec - 53 (correction) turn off 1 digit, OnOff variable not use - switch digits for Fade // this use for Fade - one digit change to another // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // note that digit turns on but not save state into OnOff variable // test - turn on only current digit (faster) do not change state of another registry bits switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 } } /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. (1000) // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { int digitOnTime; int digitOffTime; int digitSwitchTime; float digitSwitchTimeFloat; int tmpDispType; shifter.setAll(HIGH); //turn off all 6 K155ID1 shifter.write(); // set registers 74HC595 /* byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds */ // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { // tubes 0 - 5, 5-seconds if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; //0 break; } case DIMMED: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIM_VALUE; break; } case BRIGHT: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = DIGIT_DISPLAY_OFF; //1000 //digitOffTime = 995; break; } case FADE: case NORMAL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; } else { digitOnTime = DIGIT_DISPLAY_NEVER; digitOffTime = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime = DIGIT_DISPLAY_ON; digitOffTime = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime) { // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(i, currNumberArray[i]); } if (timer == digitSwitchTime) { // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); SetSN74141Chip(i,NumberArray[i]); } if (timer == digitOffTime) { digitOff(i); } } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // optimize for speed ! up to 300000 cycles/1s // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // tens of hours tube switch (value) { case 0: shifter.setPin(0, LOW); shifter.setPin(1, LOW); shifter.setPin(2, LOW); shifter.setPin(3, LOW); break; case 1: shifter.setPin(0, HIGH); shifter.setPin(1, LOW); shifter.setPin(2, LOW); shifter.setPin(3, LOW); break; case 2: shifter.setPin(0, LOW); shifter.setPin(1, HIGH); shifter.setPin(2, LOW); shifter.setPin(3, LOW); break; case 3: shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, LOW); shifter.setPin(3, LOW); break; case 4: shifter.setPin(0, LOW); shifter.setPin(1, LOW); shifter.setPin(2, HIGH); shifter.setPin(3, LOW); break; case 5: shifter.setPin(0, HIGH); shifter.setPin(1, LOW); shifter.setPin(2, HIGH); shifter.setPin(3, LOW); break; case 6: shifter.setPin(0, LOW); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, LOW); break; case 7: shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, LOW); break; case 8: shifter.setPin(0, LOW); shifter.setPin(1, LOW); shifter.setPin(2, LOW); shifter.setPin(3, HIGH); break; case 9: shifter.setPin(0, HIGH); shifter.setPin(1, LOW); shifter.setPin(2, LOW); shifter.setPin(3, HIGH); break; //case 10: //off // shifter.setPin(n, HIGH); // shifter.setPin(n + 1, HIGH); // shifter.setPin(n + 2, HIGH); // shifter.setPin(n + 3, HIGH); // break; } // nixie (20, value); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (8, value); //minutes // nixie subroutine switch by value //nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { switch (value) { case 0: shifter.setPin(4, LOW); shifter.setPin(5, LOW); shifter.setPin(6, LOW); shifter.setPin(7, LOW); break; case 1: shifter.setPin(4, HIGH); shifter.setPin(5, LOW); shifter.setPin(6, LOW); shifter.setPin(7, LOW); break; case 2: shifter.setPin(4, LOW); shifter.setPin(5, HIGH); shifter.setPin(6, LOW); shifter.setPin(7, LOW); break; case 3: shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, LOW); shifter.setPin(7, LOW); break; case 4: shifter.setPin(4, LOW); shifter.setPin(5, LOW); shifter.setPin(6, HIGH); shifter.setPin(7, LOW); break; case 5: shifter.setPin(4, HIGH); shifter.setPin(5, LOW); shifter.setPin(6, HIGH); shifter.setPin(7, LOW); break; case 6: shifter.setPin(4, LOW); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, LOW); break; case 7: shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, LOW); break; case 8: shifter.setPin(4, LOW); shifter.setPin(5, LOW); shifter.setPin(6, LOW); shifter.setPin(7, HIGH); break; case 9: shifter.setPin(4, HIGH); shifter.setPin(5, LOW); shifter.setPin(6, LOW); shifter.setPin(7, HIGH); break; } // nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { switch (value) { case 0: shifter.setPin(8, LOW); shifter.setPin(9, LOW); shifter.setPin(10, LOW); shifter.setPin(11, LOW); break; case 1: shifter.setPin(8, HIGH); shifter.setPin(9, LOW); shifter.setPin(10, LOW); shifter.setPin(11, LOW); break; case 2: shifter.setPin(8, LOW); shifter.setPin(9, HIGH); shifter.setPin(10, LOW); shifter.setPin(11, LOW); break; case 3: shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, LOW); shifter.setPin(11, LOW); break; case 4: shifter.setPin(8, LOW); shifter.setPin(9, LOW); shifter.setPin(10, HIGH); shifter.setPin(11, LOW); break; case 5: shifter.setPin(8, HIGH); shifter.setPin(9, LOW); shifter.setPin(10, HIGH); shifter.setPin(11, LOW); break; case 6: shifter.setPin(8, LOW); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, LOW); break; case 7: shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, LOW); break; case 8: shifter.setPin(8, LOW); shifter.setPin(9, LOW); shifter.setPin(10, LOW); shifter.setPin(11, HIGH); break; case 9: shifter.setPin(8, HIGH); shifter.setPin(9, LOW); shifter.setPin(10, LOW); shifter.setPin(11, HIGH); break; } // nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { switch (value) { case 0: shifter.setPin(12, LOW); shifter.setPin(13, LOW); shifter.setPin(14, LOW); shifter.setPin(15, LOW); break; case 1: shifter.setPin(12, HIGH); shifter.setPin(13, LOW); shifter.setPin(14, LOW); shifter.setPin(15, LOW); break; case 2: shifter.setPin(12, LOW); shifter.setPin(13, HIGH); shifter.setPin(14, LOW); shifter.setPin(15, LOW); break; case 3: shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, LOW); shifter.setPin(15, LOW); break; case 4: shifter.setPin(12, LOW); shifter.setPin(13, LOW); shifter.setPin(14, HIGH); shifter.setPin(15, LOW); break; case 5: shifter.setPin(12, HIGH); shifter.setPin(13, LOW); shifter.setPin(14, HIGH); shifter.setPin(15, LOW); break; case 6: shifter.setPin(12, LOW); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, LOW); break; case 7: shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, LOW); break; case 8: shifter.setPin(12, LOW); shifter.setPin(13, LOW); shifter.setPin(14, LOW); shifter.setPin(15, HIGH); break; case 9: shifter.setPin(12, HIGH); shifter.setPin(13, LOW); shifter.setPin(14, LOW); shifter.setPin(15, HIGH); break; } // nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { switch (value) { case 0: shifter.setPin(16, LOW); shifter.setPin(17, LOW); shifter.setPin(18, LOW); shifter.setPin(19, LOW); break; case 1: shifter.setPin(16, HIGH); shifter.setPin(17, LOW); shifter.setPin(18, LOW); shifter.setPin(19, LOW); break; case 2: shifter.setPin(16, LOW); shifter.setPin(17, HIGH); shifter.setPin(18, LOW); shifter.setPin(19, LOW); break; case 3: shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, LOW); shifter.setPin(19, LOW); break; case 4: shifter.setPin(16, LOW); shifter.setPin(17, LOW); shifter.setPin(18, HIGH); shifter.setPin(19, LOW); break; case 5: shifter.setPin(16, HIGH); shifter.setPin(17, LOW); shifter.setPin(18, HIGH); shifter.setPin(19, LOW); break; case 6: shifter.setPin(16, LOW); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, LOW); break; case 7: shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, LOW); break; case 8: shifter.setPin(16, LOW); shifter.setPin(17, LOW); shifter.setPin(18, LOW); shifter.setPin(19, HIGH); break; case 9: shifter.setPin(16, HIGH); shifter.setPin(17, LOW); shifter.setPin(18, LOW); shifter.setPin(19, HIGH); break; } //nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { //tube show ones of seconds // nixie (20, value); //seconds - lamp 5 -6 switch (value) { case 0: shifter.setPin(20, LOW); shifter.setPin(21, LOW); shifter.setPin(22, LOW); shifter.setPin(23, LOW); break; case 1: shifter.setPin(20, HIGH); shifter.setPin(21, LOW); shifter.setPin(22, LOW); shifter.setPin(23, LOW); break; case 2: shifter.setPin(20, LOW); shifter.setPin(21, HIGH); shifter.setPin(22, LOW); shifter.setPin(23, LOW); break; case 3: shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, LOW); shifter.setPin(23, LOW); break; case 4: shifter.setPin(20, LOW); shifter.setPin(21, LOW); shifter.setPin(22, HIGH); shifter.setPin(23, LOW); break; case 5: shifter.setPin(20, HIGH); shifter.setPin(21, LOW); shifter.setPin(22, HIGH); shifter.setPin(23, LOW); break; case 6: shifter.setPin(20, LOW); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, LOW); break; case 7: shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, LOW); break; case 8: shifter.setPin(20, LOW); shifter.setPin(21, LOW); shifter.setPin(22, LOW); shifter.setPin(23, HIGH); break; case 9: shifter.setPin(20, HIGH); shifter.setPin(21, LOW); shifter.setPin(22, LOW); shifter.setPin(23, HIGH); break; } } } if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now 1/50/1000*6 sec // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster //shifter.setAll(HIGH); int j=i*4; shifter.setPin(j, HIGH); shifter.setPin(j+1, HIGH); shifter.setPin(j+2, HIGH); shifter.setPin(j+3, HIGH); /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { DIM_VALUE = 3; if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { DIM_VALUE = MIN_DIM_DEFAULT; if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
если прочитать описание то жертв и разрушений нет. Оранжевая плазма.


Vklu4ilsja i’M Citten Lynx
0 49 0 0 100 1 0
0 5 700 100 1 0
7 100 0 1000 2 1 1
eeprom internal read 2 byte blankLeading fadeSteps – 1 49
setup now read from ds32321 – 2:48:47 year 21-6-5-doW-7
verify ds32321 – 2:48:47 year 2021-6-5
2:48:47 flag rtc 1-5-t-42.58-23.50
2:49:00 5 6 2021
55
2:50:00 5 6 2021
55 обновлений в секунду с такой настройкой без нуля вначале
это не все – в основном цикле идет 6 раз перебор по 1000 раз по каждой лампе -временную диаграмму в студию – набросал карандашем с сейчас с фотаю. А у меня 6 ламп то сразу – ну еще немножко оптимизирую цикл – да и не надо высокое коммутировать после включения каждой лампы. Включать лампы в динамике – получается очень хорошая экономия энергии, а видно их и на ярком солнце, да и совпадает яркостью с декатроном – он тоже очень в динамике работает. Из преимуществ статики – отсутствие мерцания – 50 раз в секунду не мерцает если не присматриваться, как – в тексте есть. Более высокая яркость. из недостатков – перевод 7 ватт в тепло вместо 2.5 но это можно и подправить, подобрав резисторы. Ток выхода К155ИД1 максимум 15 миллиампер – в одном только справочнике за 1986 год оказалось, при этом в серии микросхем некоторые выдерживают 40 ма – для увеличения нагрузочной способности, а основная часть 20ма. Этот чип особенный – высоковольтный. (минимально резистор 12 килоом если в статике то 2 в параллели 24к по 2 ватта. Это максимальный режим прожига цифры – не больше секунд 10. ) Рабочий ток для ИН1 это 3 – 4 ма то есть резистор 33 килоома для 170 вольт – для статики. Подсветки выключенных цифр возникают при 200 – почти незаметно и до 210 вольт, при 230 уже очень заметное свечение почти как у включенных цифр. На стабилитроне у чипа К155ИД1 устанавливается 60 вольт, максимальный ток 0.5 ма, а напряжение зажигания примерно 145 – 150 вольт, в темноте на 5 вольт больше. Для наполовину динамического режима я оставлю 15 килоом 2 ватта – все таки 2 по 30 в параллель или 7к5 последовательно по 2 ватта, превышать мощность у резистора это будет возгорание.
это вариант в статике – все проверки включил и цифры случайно не загораются – время цикла 46 в секунду. Зато внутренний цикл включает сразу 6 ламп, не переключая по одной. Яркосты выросла в 3 раза – это программа для дисплея в статике и заодно ток потребления в 3 раза почти до 6 ватт. Если загружаю эту прошивку – увеличиваю резисторы до 24 килоом – по 2 ватта а не 15 килоом по 4 ватта (рекомендую). Отличие в программе – сначала обрабатывается массив данных – время задержки во включенном состоянии у каждой из 6 ламп и во внутреннем цикле сразу 6 ламп включаются – счетчик внутреннего цикла установлен 999 а если запаивается фоторезистор – подправить в модуле программы LDR – то он будет от внешней освещенности зависеть. по коротким нажатиям – до секунды – кнопки – выводится на дисплей – время – температура с ds3231 – число циклов – 46 или 53 смотря сколько цифр 5 или 6 и эффектов – показание фоторезистора оно же яркость ламп по внутреннему циклу – 999 или 120-900 если резистор запаян. Это уже прошивка только если 6 дешифраторов и 6 ламп -повторяюсь – ее адрес есть на github in1clock-mod6.ino
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // 500 //1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // 499 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 2000 // Maximum value we can set to #define DISPLAY_COUNT_MIN 400 // Minimum value we can set to #define MIN_DIM_DEFAULT 120 // The default minimum dim count #define MIN_DIM_MIN 10 // The minimum dim count #define MIN_DIM_MAX 350 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 60 //100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 450 //700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 4 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second //50 is 1 sec #define FADE_STEPS_DEFAULT 50 #define FADE_STEPS_MAX 200 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; int digitOffCount = DIGIT_DISPLAY_OFF; int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value //const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; //200 int DIM_VALUE = 25; //200 is too bright int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = true; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT_PULLUP ); // set the input pin 1 // add resistor // вернул настройку HV и сброс до заводских настроек (нажать кнопку при включении) /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // Set up timer 2 like timer 0 (for RGB leds) TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); TCCR2B = (1 << CS22); // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset /* for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } */ // mark that we need the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } fadeSteps=49; // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера // setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } if (doTestPattern) { boolean oldUseLDR = useLDR; // byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); // checkHVVoltage(); // setLedsTestPattern(nowMillis); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; blankTubes = false; } } useLDR = oldUseLDR; // backlightMode = oldBacklightMode; } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); // setTime(12, 34, 56, 1, 3, 2017); // getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } // performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { if (debug){ Serial.println(" butt 2s "); } // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { if (debug){ Serial.println(" button 1s p-r "); } currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); // 120 dark (night) 999 bright - day fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 0; // 0 - не дергаю однорукого бандита acp off } } else { acpOffset = 1; } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 7) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter but useless - current set as normal light OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (second() == 15) { // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; // no ldr but useLDR true (test) //sensorSmoothedResult = dimDark +1; sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage //checkHVVoltage(); // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) one time each minute if (useRTC) getRTCTime(); } digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); /* nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } shifter.setAll(HIGH); // off all tubes shifter.write(); //send changes to the chain and display them */ } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now (OK) // 46 impression per sec - 53 (correction) turn off 1 digit, OnOff variable not use - switch digits for Fade // this use for Fade - one digit change to another // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // note that digit turns on but not save state into OnOff variable OnOff[digit]= 0; // now digit turns off (on for transition) .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) // test - turn on only current digit (faster) do not change state of another registry bits switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 } } /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. (1000) // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { int digitOnTime[6]; int digitOffTime[6]; int digitSwitchTime[6]; float digitSwitchTimeFloat; int tmpDispType; shifter.setAll(HIGH); //turn off all 6 K155ID1 shifter.write(); // set registers 74HC595 /* byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds */ // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { // tubes 0 - 5, 5-seconds if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime[i] = DIGIT_DISPLAY_NEVER; digitOffTime[i] = DIGIT_DISPLAY_ON; //0 break; } case DIMMED: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = DIM_VALUE; break; } case BRIGHT: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i ]= DIGIT_DISPLAY_OFF; //1000 //digitOffTime = 995; break; } case FADE: case NORMAL: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; } else { digitOnTime[i] = DIGIT_DISPLAY_NEVER; digitOffTime[i] = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime[i] = DIGIT_DISPLAY_OFF; if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; digitSwitchTime[i] = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime[i] = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } // 6 tubes at one time } for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime[0]) { // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(0, currNumberArray[0]); } if (timer == digitOnTime[1]) { digitOn(1, currNumberArray[1]); } if (timer == digitOnTime[2]) { digitOn(2, currNumberArray[2]); } if (timer == digitOnTime[3]) { digitOn(3, currNumberArray[3]); } if (timer == digitOnTime[4]) { digitOn(4, currNumberArray[4]); } if (timer == digitOnTime[5]) { digitOn(5, currNumberArray[5]); } if (timer == digitSwitchTime[0]) { // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); //fade or transition SetSN74141Chip(0,NumberArray[0]); } if (timer == digitSwitchTime[1]) { SetSN74141Chip(1,NumberArray[1]); } if (timer == digitSwitchTime[2]) { SetSN74141Chip(2,NumberArray[2]); } if (timer == digitSwitchTime[3]) { SetSN74141Chip(3,NumberArray[3]); } if (timer == digitSwitchTime[4]) { SetSN74141Chip(4,NumberArray[4]); } if (timer == digitSwitchTime[5]) { SetSN74141Chip(5,NumberArray[5]); } if (timer == digitOffTime[0]) { digitOff(0); } if (timer == digitOffTime[1]) { digitOff(1); } if (timer == digitOffTime[2]) { digitOff(2); } if (timer == digitOffTime[3]) { digitOff(3); } if (timer == digitOffTime[4]) { digitOff(4); } if (timer == digitOffTime[5]) { digitOff(5); } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // optimize for speed ! up to 300000 cycles/1s // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // tens of hours tube // nixie (20, value); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (8, value); //minutes // nixie subroutine switch by value nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { //tube show ones of seconds nixie (20, value); //seconds - lamp 5 -6 } } if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now 1/50/1000*6 sec // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster //shifter.setAll(HIGH); int j=i*4; shifter.setPin(j, HIGH); shifter.setPin(j+1, HIGH); shifter.setPin(j+2, HIGH); shifter.setPin(j+3, HIGH); if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { DIM_VALUE = 3; if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { DIM_VALUE = MIN_DIM_DEFAULT; if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
исправил 5 ошибок – заработал режим плавной смены 2 цифр ( значение fade надо ставить 45 49 в секунду ) и число циклов больших в секунду не сильно упало 46 и 49 если без плавной смены цифр – не моргает. Программа для статического дисплея – 6 ламп 6 дешифраторов , 175 – 560 на декатроне 4и 7 десятых на полутора витках для логики, 12 входное пол ампера – яркость для статики максимальная – но включил фоторезистор. LDR used . Резисторы анодные запаяны 18 килоом по 2 ватта на лампу – режим прожига ламп осторожно – не больше минуты на цифру. Убран глюк с путаницей при точно нулях секунд – когда считывалось время с чипа то сбивались цифры которые показывались при плавном переходе. Программа без нажатий на кнопку – считывает время с чипа раз в минуту – чип запитан от батарейки и от 5 вольт через 2 диода лапку батарейного питания, это важно, выводит время и температуру и число на 50 секунде. Схема выше. Цифры в основном цикле не гасятся, в маленьких 2 циклах обрабатываются значения и во втором сразу вывод на дисплей из 6 ламп. во втором маленьком цикле 1000 единиц таймера – примерно по 20 микросекунд – это минимальное время зажигания цифры , на самую маленькую яркость 200 мкс а на большую 20мс – то есть на 1/50 секунды почти включение. ( не путать миллионные секунды и тысячные) – если не пугаемся совсем и нет никаких противопоказаний – по медицине – от быстро движущихся картинок можно … не буду говорить , короче если в видеоигры играешь нормально и по скорой не забирают то можно посмотреть просто глазами 300 тысяч вспышек в секунду – немножко выше написано как, если со здоровьем все норм то это не опасно. .. теперь динамика только для уменьшения яркости и красивых эффектов – другими словами. * еще исправления – фантомные цифры в режиме fade не больше секунды и не больше 2./3 яркости основных . Интересное кино хоть в трубки ИН1 не добавлена ртуть они включаются спокойно 20000 раз в секунду – 1 задержку я не увидел а 2 – внутренний цикл 20 микросекунд *2 лампа загорается- видно.
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // 500 //1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // 499 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 1001 // Maximum value we can set to #define DISPLAY_COUNT_MIN 300 // Minimum value we can set to #define MIN_DIM_DEFAULT 120 // The default minimum dim count #define MIN_DIM_MIN 10 // The minimum dim count #define MIN_DIM_MAX 350 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 60 //100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 450 //700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 6 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second //50 is 1 sec #define FADE_STEPS_DEFAULT 42 #define FADE_STEPS_MAX 130 #define FADE_STEPS_MIN 20 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {0, 0, 0, 0, 0, 0}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached byte threesectimer = 0; int digitOnTime[6]; int digitOffTime[6]; int digitSwitchTime[6]= {0, 0, 0, 0, 0, 0}; // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 // 50 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; //45 int digitOffCount = DIGIT_DISPLAY_OFF; //999 int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = digitOffCount / fadeSteps; //DIGIT_DISPLAY_COUNT // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value //const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; //200 int DIM_VALUE = 25; //200 is too bright int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = true; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT_PULLUP ); // set the input pin 1 // add resistor // вернул настройку HV и сброс до заводских настроек (нажать кнопку при включении) /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // Set up timer 2 like timer 0 (for RGB leds) TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); TCCR2B = (1 << CS22); // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset /* for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } */ // mark that we need the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } // fadeSteps=49; // for test now 52 // 46 big cycles per second *1000 display timer 46000 установок регистров в секунду, а если 2 цифры сразу то 100000 (fade) // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера // setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // если зависает то смотреть монитор порта и закомментировать строку ниже i found what may hung up if (useRTC) getRTCTime(); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } if (doTestPattern) { boolean oldUseLDR = useLDR; // byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); // checkHVVoltage(); // setLedsTestPattern(nowMillis); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; blankTubes = false; } } useLDR = oldUseLDR; // backlightMode = oldBacklightMode; } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); // setTime(12, 34, 56, 1, 3, 2017); // getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { if (debug){ Serial.println(" butt 2s "); } // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { if (debug){ Serial.println(" button 1s p-r "); } currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); // 120 dark (night) 999 bright - day fadeStep = digitOffCount / fadeSteps; // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 0; // 0 - не дергаю однорукого бандита acp off } } else { acpOffset = 1; // 0 ? 1 is anti poison on // effects at 15 +50 seconds - do anti-poison too } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 7) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter // but useless - current set as normal light // dynamic mode - max bright OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); //50 .. 45 not more than 1 second = 46 // 49 cycles displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (second() == 15) { // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); // fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // if bright 1000 = 100% 1000 /50 =20 fadeStep = digitOffCount / fadeSteps; break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); // fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; fadeStep = digitOffCount / fadeSteps; break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; // no ldr but useLDR true (test) =dimBright (999) // фоторезистор - если не запаян то установить значение на полную яркость sensorSmoothedResult = dimDark +1; //sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; threesectimer= threesectimer+1 ; if (threesectimer==3) { threesectimer=0; int digitSwitchTime[6]= {0, 0, 0, 0, 0, 0}; //clear fade effect each 3 seconds //was 3-4 digit turn on at one time in 2 -3 tubes tens - ones seconds //byte OnOff[6] = {0, 0, 0, 0, 0, 0}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); // transition.start(nowMillis); // убрал - моргает /* digitOff(5); digitOff(4); digitOff(3); digitOff(2); digitOff(1); digitOff(0); */ } // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage //checkHVVoltage(); // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { // digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); /* nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } */ //shifter.setAll(HIGH); // off all tubes // shifter.write(); //send changes to the chain and display them /* * время с ds3231 - раз в час поменял * allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; // initialise the slots values temperature // после чтения чипа часов есть ошибка - засветка третьей одновременно цифры нуля или единички на 4 лампах кроме часовых! loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); */ int digitSwitchTime[6]= {0, 0, 0, 0, 0, 0}; // OK fade 2 digit together Works // заработал режим переключения с плавным гашением was glitch 3 digits together each minute.. } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { // считывание ds3231 перенес на 1 раз в час .. глюк - сбивается режим fade .. не только - сбрасываю еще digitSwithcTime if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) one time each minute перенес на каждый час if (useRTC) getRTCTime(); } // initialise the slots values temperature // после чтения чипа часов есть ошибка - засветка третьей одновременно цифры нуля или единички на 4 лампах кроме часовых! loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now (OK) // 46 impression per sec - 53 (correction) turn off 1 digit, OnOff variable not use - switch digits for Fade // this use for Fade - one digit change to another // Fade - 60 steps - each step * 120 minDim // 30-300 times see OK ?? (max bright 1000) not more 1 second - when 46 impr/ sec check - not more 45 // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // note that digit turns on but not save state into OnOff variable OnOff[digit]= 1; // now digit turns off (on for transition) .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) // test - turn on only current digit (faster) do not change state of another registry bits switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 } } //useless .. if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. (1000) // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { float digitSwitchTimeFloat; int tmpDispType; // digitOff(5); //all correctly but .. 36 cycles per second // digitOff(4); // digitOff(3); // digitOff(2); // digitOff(1); // digitOff(0); // shifter.setAll(HIGH); //turn off all 6 K155ID1 // shifter.write(); // set registers 74HC595 /* byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds */ // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { // tubes 0 - 5, 5-seconds if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime[i] = DIGIT_DISPLAY_NEVER; digitOffTime[i] = DIGIT_DISPLAY_ON; //0 break; } case DIMMED: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 digitOffTime[i] = DIM_VALUE; break; } case BRIGHT: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 0 .... 1000 on -0 *20mks off 20000 mks ~~ always on digitOffTime[i]= DIGIT_DISPLAY_OFF; //1000 //digitOffTime = 995; break; } case FADE: case NORMAL: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 digitOffTime[i] = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; } else { digitOnTime[i] = DIGIT_DISPLAY_NEVER; // -1 = off all cycle digitOffTime[i] = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime[i] = DIGIT_DISPLAY_OFF; //1000 if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade .. scroll fadeState[i] = 0; currNumberArray[i] = currNumberArray[i] - 1; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { // first time currNumberArray[i] = 0; if (fadeState[i] == 0) { // Start the fade fadeState[i] = fadeSteps; // set value for Fade - 46 impr/sec -> 45 max, 49 --> 47 digitSwitchTime[i] = (int) fadeState[i] * fadeStep; } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; //1000 } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime[i] = (int) fadeState[i] * fadeStep; } } else { digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; } // 6 tubes at one time first loop } // 6 tubes set - inner cycle 1000 times (dispCount) (change -2-nd loop all together 6 digits) for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime[0]) { //fade or transition - turn on together 2 digit // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(0, currNumberArray[0]); } if (timer == digitOnTime[1]) { digitOn(1, currNumberArray[1]); } if (timer == digitOnTime[2]) { digitOn(2, currNumberArray[2]); } if (timer == digitOnTime[3]) { digitOn(3, currNumberArray[3]); } if (timer == digitOnTime[4]) { digitOn(4, currNumberArray[4]); } if (timer == digitOnTime[5]) { digitOn(5, currNumberArray[5]); } if (timer == digitSwitchTime[0]) { //fade or transition - turn on together 2 digit // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); SetSN74141Chip(0,NumberArray[0]); } if (timer == digitSwitchTime[1]) { SetSN74141Chip(1,NumberArray[1]); } if (timer == digitSwitchTime[2]) { SetSN74141Chip(2,NumberArray[2]); } if (timer == digitSwitchTime[3]) { SetSN74141Chip(3,NumberArray[3]); } if (timer == digitSwitchTime[4]) { SetSN74141Chip(4,NumberArray[4]); } if (timer == digitSwitchTime[5]) { SetSN74141Chip(5,NumberArray[5]); } if (timer == digitOffTime[0]) { digitOff(0); } if (timer == digitOffTime[1]) { digitOff(1); } if (timer == digitOffTime[2]) { digitOff(2); } if (timer == digitOffTime[3]) { digitOff(3); } if (timer == digitOffTime[4]) { digitOff(4); } if (timer == digitOffTime[5]) { digitOff(5); } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // optimize for speed ! up to 300000 cycles/1s // //next try optimize - 6 digit at one time // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // tens of hours tube // nixie (20, value); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (8, value); //minutes // nixie subroutine switch by value nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { //tube show ones of seconds nixie (20, value); //seconds - lamp 5 -6 } } // turn off (dynamic) 1/50000 s * digitOffTime if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now 1/50/1000*6 sec // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); TCNT1 = 0; // Thanks Phil! TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster //shifter.setAll(HIGH); int j=i*4; shifter.setPin(j, HIGH); shifter.setPin(j+1, HIGH); shifter.setPin(j+2, HIGH); shifter.setPin(j+3, HIGH); if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { DIM_VALUE = 3; if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { DIM_VALUE = MIN_DIM_DEFAULT; if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
исправление для эффекта плавного переключения ламп – и еще раз оптимизация времени выполнения программы – пришлось взяться за работу программиста по микроконтроллерам и встроеным устройствам – с опытом работы начиная с переделки синклера АОНа в 1996 и дверного замка в 2001 году. ( Выделил себе виртуально 2 часа работы.. )
Замок кстати появится здесь он на Ардуино и считывает американскую морскую метку – тот самый брелок EM-Marin. Он позволяет запускать например в офис или на склад нужных людей и при этом не заставлять охранника каждого проверять – в журнале записывается кто прошел когда и в какую сторону, по ключам видно, охранник или секретарь смотрит только на монитор если надо, может нажать кнопку если надо кого -то пропустить без ключа.
Кстати – эта ардуинка позволяет многие вещи сделать тем кто не разбирался с микрокомпьютерами или даже электроникой – просто прочитав инструкцию как это делается.
ссылка на видео
http://youtu.be/vxJvNRIcBCk
исправленная программа .. я сначала подумал что накосячил перепутал названия переменных и соответственно цифры которые одна сменяет другую но оказалось намного более красиво воспринимается – даже на секундной цифре. Поэтому этот эффект оставляю. для включения 10 опцию – fade установить в единичку
#include <avr/io.h> #include <EEPROM.h> #include <Wire.h> #include <avr/wdt.h> #include <Shifter.h> #include <DS3231.h> // https://github.com/NorthernWidget/DS3231 (Wickert 1.0.2) ? //install from lib manager! #include <Time.h> #include <TimeLib.h> // https://github.com/michaelmargolis/arduino_time //Установить через менеджер библиотек // Other parts of the code, broken out for clarity //make folder in arduino libraries - copy to folder #include "ClockButton.h" #include "Transition.h" /* name=DS3231 version=1.0.7 author=Andrew Wickert <awickert@umn.edu>, Eric Ayars, Jean-Claude Wippler, Northern Widget LLC <info@northernwidget.com> maintainer=Andrew Wickert <awickert@umn.edu> sentence=Arduino library for the DS3231 real-time clock (RTC) paragraph=Abstracts functionality for clock reading, clock setting, and alarms for the DS3231 high-precision real-time clock. This is a splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries. category=Timing url=https://github.com/NorthernWidget/DS3231 architectures=* includes=DS3231.h */ /* serial monitor ( battery voltage >3v) reset pin NC or 100k + to +5v 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 7:34:56 year 21-5-2-doW-4 verify ds32321 - 25:165:165 year 117-85-165 0:9:48 flag rtc 1-1-t-41.68-21.50 DS3231_T=21 DS3231_rd0=48:9:0-7-1-1-0 0:09:59 1 1 2000 20 DS3231_T=128 41.45 wrong read DS3231! DS3231_T=21 50 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 0 50 verify this write to ds32321 - 2:22:29 year 0-1-2-doW-4 verify ds32321 - 2:22:29 year 208-1-2 2:22:29 flag rtc 1-2-t-41.45-21.00 DS3231_T_1-st-byte=21 DS3231_rd0=2:22:29-day-4-2-1-2000 2:23:00 2 1 2000 20 DS3231_T-2byte=21.0 F 41.45 DS3231_T=21.0 */ #define SER_Pin 11 //SER_IN //data 14 pin 74hc595 #define RCLK_Pin 9 //L_CLOCK //latch rclk 12 74hc595 #define SRCLK_Pin 8 //CLOCK //clock srclk 11 74hc595 // RTC address #define RTC_I2C_ADDRESS 0x68 #define DS3231_I2C_ADDRESS 0x68 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // Basic settings #define MODE_12_24 7 // 0 = 24, 1 = 12 #define HOUR_MODE_DEFAULT false #define MODE_LEAD_BLANK 8 // 1 = blanked #define LEAD_BLANK_DEFAULT false #define MODE_SCROLLBACK 9 // 1 = use scrollback #define SCROLLBACK_DEFAULT false #define MODE_FADE 10 // 1 = use fade #define FADE_DEFAULT false #define MODE_DATE_FORMAT 11 // #define MODE_DAY_BLANKING 12 // #define MODE_HR_BLNK_START 13 // #define MODE_HR_BLNK_END 14 // #define MODE_SUPPRESS_ACP 15 // 1 = suppress ACP when fully dimmed #define SUPPRESS_ACP_DEFAULT true #define MODE_USE_LDR 16 // 1 = use LDR, 0 = don't (and have 100% brightness) #define MODE_USE_LDR_DEFAULT true #define MODE_BLANK_MODE 17 // #define MODE_BLANK_MODE_DEFAULT BLANK_MODE_BOTH // Display tricks #define MODE_FADE_STEPS_UP 18 // #define MODE_FADE_STEPS_DOWN 19 // #define MODE_DISPLAY_SCROLL_STEPS_UP 20 // #define MODE_DISPLAY_SCROLL_STEPS_DOWN 21 // #define MODE_SLOTS_MODE 22 // // I2C Interface definition #define I2C_SLAVE_ADDR 0x69 #define I2C_TIME_UPDATE 0x00 #define I2C_GET_OPTIONS 0x01 #define I2C_SET_OPTION_12_24 0x02 #define I2C_SET_OPTION_BLANK_LEAD 0x03 #define I2C_SET_OPTION_SCROLLBACK 0x04 #define I2C_SET_OPTION_SUPPRESS_ACP 0x05 #define I2C_SET_OPTION_DATE_FORMAT 0x06 #define I2C_SET_OPTION_DAY_BLANKING 0x07 #define I2C_SET_OPTION_BLANK_START 0x08 #define I2C_SET_OPTION_BLANK_END 0x09 #define I2C_SET_OPTION_FADE_STEPS 0x0a #define I2C_SET_OPTION_SCROLL_STEPS 0x0b #define I2C_SET_OPTION_BACKLIGHT_MODE 0x0c #define I2C_SET_OPTION_RED_CHANNEL 0x0d #define I2C_SET_OPTION_GREEN_CHANNEL 0x0e #define I2C_SET_OPTION_BLUE_CHANNEL 0x0f #define I2C_SET_OPTION_CYCLE_SPEED 0x10 #define I2C_SHOW_IP_ADDR 0x11 #define I2C_SET_OPTION_FADE 0x12 #define I2C_SET_OPTION_USE_LDR 0x13 #define I2C_SET_OPTION_BLANK_MODE 0x14 #define I2C_SET_OPTION_SLOTS_MODE 0x15 #define I2C_SET_OPTION_MIN_DIM 0x16 #define I2C_DATA_SIZE 22 #define I2C_PROTOCOL_NUMBER 54 #define EE_12_24 1 // 12 or 24 hour mode #define EE_FADE_STEPS 2 // How quickly we fade, higher = slower #define EE_DATE_FORMAT 3 // Date format to display #define EE_DAY_BLANKING 4 // Blanking setting #define EE_DIM_DARK_LO 5 // Dimming dark value #define EE_DIM_DARK_HI 6 // Dimming dark value #define EE_BLANK_LEAD_ZERO 7 // If we blank leading zero on hours #define EE_DIGIT_COUNT_HI 8 // The number of times we go round the main loop #define EE_DIGIT_COUNT_LO 9 // The number of times we go round the main loop #define EE_SCROLLBACK 10 // if we use scollback or not #define EE_FADE 11 // if we use fade or not #define EE_PULSE_LO 12 // The pulse on width for the PWM mode #define EE_PULSE_HI 13 // The pulse on width for the PWM mode #define EE_SCROLL_STEPS 14 // The steps in a scrollback #define EE_BACKLIGHT_MODE 15 // The back light node #define EE_DIM_BRIGHT_LO 16 // Dimming bright value #define EE_DIM_BRIGHT_HI 17 // Dimming bright value #define EE_DIM_SMOOTH_SPEED 18 // Dimming adaptation speed #define EE_RED_INTENSITY 19 // Red channel backlight max intensity #define EE_GRN_INTENSITY 20 // Green channel backlight max intensity #define EE_BLU_INTENSITY 21 // Blue channel backlight max intensity #define EE_HV_VOLTAGE 22 // The HV voltage we want to use #define EE_SUPPRESS_ACP 23 // Do we want to suppress ACP during dimmed time #define EE_HOUR_BLANK_START 24 // Start of daily blanking period #define EE_HOUR_BLANK_END 25 // End of daily blanking period #define EE_CYCLE_SPEED 26 // How fast the color cycling does it's stuff #define EE_PWM_TOP_LO 27 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_PWM_TOP_HI 28 // The PWM top value if we know it, 0xFF if we need to calculate #define EE_HVG_NEED_CALIB 29 // 1 if we need to calibrate the HVGenerator, otherwise 0 #define EE_MIN_DIM_LO 30 // The min dim value #define EE_MIN_DIM_HI 31 // The min dim value #define EE_ANTI_GHOST 32 // The value we use for anti-ghosting #define EE_NEED_SETUP 33 // used for detecting auto config for startup. By default the flashed, empty EEPROM shows us we need to do a setup #define EE_USE_LDR 34 // if we use the LDR or not (if we don't use the LDR, it has 100% brightness #define EE_BLANK_MODE 35 // blank tubes, or LEDs or both #define EE_SLOTS_MODE 36 // Show date every now and again // Display mode, set per digit #define BLANKED 0 #define DIMMED 1 #define FADE 2 #define NORMAL 3 #define BLINK 4 #define SCROLL 5 #define BRIGHT 6 // const byte rgb_backlight_curve[] = {0, 16, 32, 48, 64, 80, 99, 112, 128, 144, 160, 176, 192, 208, 224, 240, 255}; #define DIGIT_COUNT 6 // 6 ламп или 4 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define BACKLIGHT_MIN 0 //подсветку отключил #define BACKLIGHT_FIXED 0 // Just define a colour and stick to it #define BACKLIGHT_PULSE 1 // pulse the defined colour #define BACKLIGHT_CYCLE 2 // cycle through random colours #define BACKLIGHT_FIXED_DIM 3 // A defined colour, but dims with bulb dimming #define BACKLIGHT_PULSE_DIM 4 // pulse the defined colour, dims with bulb dimming #define BACKLIGHT_CYCLE_DIM 5 // cycle through random colours, dims with bulb dimming #define BACKLIGHT_MAX 5 #define BACKLIGHT_DEFAULT 0 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 // Display handling #define DIGIT_DISPLAY_COUNT 1000 // 500 //1000 // The number of times to traverse inner fade loop per digit #define DIGIT_DISPLAY_ON 0 // Switch on the digit at the beginning by default #define DIGIT_DISPLAY_OFF 999 // 499 // Switch off the digit at the end by default #define DIGIT_DISPLAY_NEVER -1 // When we don't want to switch on or off (i.e. blanking) #define DISPLAY_COUNT_MAX 1001 // Maximum value we can set to #define DISPLAY_COUNT_MIN 300 // Minimum value we can set to #define MIN_DIM_DEFAULT 120 // The default minimum dim count #define MIN_DIM_MIN 10 // The minimum dim count #define MIN_DIM_MAX 350 // The maximum dim count #define SENSOR_LOW_MIN 0 #define SENSOR_LOW_MAX 900 #define SENSOR_LOW_DEFAULT 60 //100 // Dark #define SENSOR_HIGH_MIN 0 #define SENSOR_HIGH_MAX 900 #define SENSOR_HIGH_DEFAULT 450 //700 // Bright #define SENSOR_SMOOTH_READINGS_MIN 1 #define SENSOR_SMOOTH_READINGS_MAX 255 #define SENSOR_SMOOTH_READINGS_DEFAULT 100 // Speed at which the brighness adapts to changes #define BLINK_COUNT_MAX 25 // The number of impressions between blink state toggle // The target voltage we want to achieve hv gen not use (mc34063) #define HVGEN_TARGET_VOLTAGE_DEFAULT 180 #define HVGEN_TARGET_VOLTAGE_MIN 150 #define HVGEN_TARGET_VOLTAGE_MAX 200 // The PWM parameters #define PWM_TOP_DEFAULT 10000 #define PWM_TOP_MIN 300 #define PWM_TOP_MAX 10000 #define PWM_PULSE_DEFAULT 200 #define PWM_PULSE_MIN 100 #define PWM_PULSE_MAX 500 #define PWM_OFF_MIN 50 // How quickly the scroll works #define SCROLL_STEPS_DEFAULT 6 #define SCROLL_STEPS_MIN 1 #define SCROLL_STEPS_MAX 40 #define ANTI_GHOST_MIN 0 //for hv gen // sets into eeprom config but not use #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 // The number of dispay impessions we need to fade by default // 100 is about 1 second //50 is 1 sec #define FADE_STEPS_DEFAULT 42 #define FADE_STEPS_MAX 49 #define FADE_STEPS_MIN 5 #define SECS_MAX 60 #define MINS_MAX 60 #define HOURS_MAX 24 // Clock modes - normal running is MODE_TIME, other modes accessed by a middle length ( 1S < press < 2S ) button press #define MODE_MIN 0 #define MODE_TIME 0 // Time setting, need all six digits, so no flashing mode indicator #define MODE_HOURS_SET 1 #define MODE_MINS_SET 2 #define MODE_SECS_SET 3 #define MODE_DAYS_SET 4 #define MODE_MONTHS_SET 5 #define MODE_YEARS_SET 6 // HV generation #define MODE_TARGET_HV_UP 28 // #define MODE_TARGET_HV_DOWN 29 // #define MODE_PULSE_UP 30 // #define MODE_PULSE_DOWN 31 // #define MODE_MIN_DIM_UP 32 // #define MODE_MIN_DIM_DOWN 33 // #define MODE_ANTI_GHOST_UP 34 // #define MODE_ANTI_GHOST_DOWN 35 // // Temperature #define MODE_TEMP 36 // // Software Version #define MODE_VERSION 37 // // Tube test - all six digits, so no flashing mode indicator #define MODE_TUBE_TEST 38 #define MODE_MAX 38 // Pseudo mode - burn the tubes and nothing else #define MODE_DIGIT_BURN 99 // Digit burn mode - accesible by super long press // Temporary display modes - accessed by a short press ( < 1S ) on the button when in MODE_TIME #define TEMP_MODE_MIN 0 #define TEMP_MODE_DATE 0 // Display the date for 5 S #define TEMP_MODE_TEMP 1 // Display the temperature for 5 S #define TEMP_MODE_LDR 2 // Display the normalised LDR reading for 5S, returns a value from 100 (dark) to 999 (bright) #define TEMP_MODE_VERSION 3 // Display the version for 5S #define TEMP_IP_ADDR12 4 // IP xxx.yyy.zzz.aaa: xxx.yyy #define TEMP_IP_ADDR34 5 // IP xxx.yyy.zzz.aaa: zzz.aaa #define TEMP_IMPR 6 // number of impressions per second #define TEMP_MODE_MAX 6 #define DATE_FORMAT_MIN 0 #define DATE_FORMAT_YYMMDD 0 #define DATE_FORMAT_MMDDYY 1 #define DATE_FORMAT_DDMMYY 2 #define DATE_FORMAT_MAX 2 #define DATE_FORMAT_DEFAULT 2 #define DAY_BLANKING_MIN 0 #define DAY_BLANKING_NEVER 0 // Don't blank ever (default) #define DAY_BLANKING_WEEKEND 1 // Blank during the weekend #define DAY_BLANKING_WEEKDAY 2 // Blank during weekdays #define DAY_BLANKING_ALWAYS 3 // Always blank #define DAY_BLANKING_HOURS 4 // Blank between start and end hour every day #define DAY_BLANKING_WEEKEND_OR_HOURS 5 // Blank between start and end hour during the week AND all day on the weekend #define DAY_BLANKING_WEEKDAY_OR_HOURS 6 // Blank between start and end hour during the weekends AND all day on week days #define DAY_BLANKING_WEEKEND_AND_HOURS 7 // Blank between start and end hour during the weekend #define DAY_BLANKING_WEEKDAY_AND_HOURS 8 // Blank between start and end hour during week days #define DAY_BLANKING_MAX 8 #define DAY_BLANKING_DEFAULT 0 #define BLANK_MODE_MIN 0 #define BLANK_MODE_TUBES 0 // Use blanking for tubes only #define BLANK_MODE_LEDS 1 // Use blanking for LEDs only #define BLANK_MODE_BOTH 2 // Use blanking for tubes and LEDs #define BLANK_MODE_MAX 2 #define BLANK_MODE_DEFAULT 2 #define CYCLE_SPEED_MIN 4 #define CYCLE_SPEED_MAX 64 #define CYCLE_SPEED_DEFAULT 10 #define ANTI_GHOST_MIN 0 #define ANTI_GHOST_MAX 50 #define ANTI_GHOST_DEFAULT 0 #define TEMP_DISPLAY_MODE_DUR_MS 5000 #define USE_LDR_DEFAULT true //light detect resistor // фоторезистор если сделаю на статике регулировку без дерганий // можно снижать напряжение на mc34063 или пробовать гасить цифры и включать 1 - 2 -3 -4 -5 циклов из 10 // сейчас время цикла 50 мс - это может быть дергание - убрать задержку и будет 6 - 10 мс что не заметно сильно мерцание // Limit on the length of time we stay in test mode #define TEST_MODE_MAX_MS 60000 #define SLOTS_MODE_MIN 0 #define SLOTS_MODE_NONE 0 // Don't use slots effect #define SLOTS_MODE_1M_SCR_SCR 1 // use slots effect every minute, scroll in, scramble out #define SLOTS_MODE_MAX 1 #define SLOTS_MODE_DEFAULT 1 #define MAX_WIFI_TIME 5 #define DO_NOT_APPLY_LEAD_0_BLANK false #define APPLY_LEAD_0_BLANK true // button input #define inputPin1 7 // package pin 13 // PD7 //d7 - Single button operation with software debounce #define sensorPin A0 // Package pin 23 // PC0 // Analog input pin for HV sense: HV divided through 390k and 4k7 divider, using 5V reference #define LDRPin A1 // Package pin 24 // PC1 // Analog input for Light dependent resistor. //********************************************************************************** Transition transition(500, 1000, 3000); // ********************** HV generator variables ********************* int hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; int pwmTop = PWM_TOP_DEFAULT; int pwmOn = PWM_PULSE_DEFAULT; // All-In-One Rev1 has a mix up in the tube wiring. All other clocks are // correct. #define NOT_AIO_REV1 // [AIO_REV1,NOT_AIO_REV1] // Used for special mappings of the K155ID1 -> digit (wiring aid) // allows the board wiring to be much simpler #ifdef AIO_REV1 // This is a mapping for All-In-One Revision 1 ONLY! Not generally used. byte decodeDigit[16] = {3,2,8,9,0,1,5,4,6,7,10,10,10,10,10,10}; #else byte decodeDigit[16] = {2,3,7,6,4,5,1,0,9,8,10,10,10,10,10,10}; #endif // Driver pins for the anodes //byte anodePins[6] = {ledPin_a_1, ledPin_a_2, ledPin_a_3, ledPin_a_4, ledPin_a_5, ledPin_a_6}; // precalculated values for turning on and off the HV generator // Put these in TCCR1B to turn off and on byte tccrOff; byte tccrOn; int rawHVADCThreshold; double sensorHVSmoothed = 0; #define NUM_REGISTERS 3 //how many registers are in the chain bool debug = false; // if (debug) // works without serial connection if debug=false byte zero = 0x00; int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // use Clock. (DS3231 lib), RTClib for subroutine code from in12 project // ************************ Display management ************************ byte NumberArray[6] = {0, 0, 0, 0, 0, 0}; byte currNumberArray[6] = {10, 10, 10, 10, 10, 10}; byte displayType[6] = {FADE, FADE, FADE, FADE, FADE, FADE}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; byte OnOff[6] = {1, 1, 1, 1, 1, 1}; //current state of digit at this time - use for dimming - blink - fade byte ourIP[4] = {0, 0, 0, 0}; // set by the WiFi module, if attached byte threesectimer = 0; int digitOnTime[6]; int digitOffTime[6]; int digitSwitchTime[6]= {0, 0, 0, 0, 0, 0}; // how many fade steps to increment (out of DIGIT_DISPLAY_COUNT) each impression // 100 // 50 is about 1 second int fadeSteps = FADE_STEPS_DEFAULT; //45 int digitOffCount = DIGIT_DISPLAY_OFF; //999 int scrollSteps = SCROLL_STEPS_DEFAULT; boolean scrollback = true; boolean fade = true; byte antiGhost = ANTI_GHOST_DEFAULT; // not use - approx. 189 v max int dispCount = DIGIT_DISPLAY_COUNT + antiGhost; float fadeStep = digitOffCount / fadeSteps; //DIGIT_DISPLAY_COUNT //int fadeStep // For software blinking int blinkCounter = 0; boolean blinkState = true; // leading digit blanking boolean blankLeading = false; // Dimming value //const int DIM_VALUE = DIGIT_DISPLAY_COUNT / 5; //200 int DIM_VALUE = 25; //200 is too bright int minDim = MIN_DIM_DEFAULT; unsigned int tempDisplayModeDuration; // time for the end of the temporary display int tempDisplayMode; int acpOffset = 0; // Used to provide one arm bandit scolling int acpTick = 0; // The number of counts before we scroll boolean suppressACP = true; byte slotsMode = SLOTS_MODE_DEFAULT; byte currentMode = MODE_TIME; // Initial cold start mode byte nextMode = currentMode; byte blankHourStart = 0; byte blankHourEnd = 0; byte blankMode = 0; boolean blankTubes = false; boolean blankLEDs = false; // ************************ Ambient light dimming ************************ int dimDark = SENSOR_LOW_DEFAULT; int dimBright = SENSOR_HIGH_DEFAULT; double sensorLDRSmoothed = 0; double sensorFactor = (double)(DIGIT_DISPLAY_OFF) / (double)(dimBright - dimDark); int sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; int sensorSmoothCountHV = SENSOR_SMOOTH_READINGS_DEFAULT / 8; boolean useLDR = true; DS3231 Clock; //initaize shifter using the Shifter library Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS); // State variables for detecting changes byte lastSec; unsigned long nowMillis = 0; unsigned long lastCheckMillis = 0; byte dateFormat = DATE_FORMAT_DEFAULT; byte dayBlanking = DAY_BLANKING_DEFAULT; boolean blanked = false; byte blankSuppressStep = 0; // The press we are on: 1 press = suppress for 1 min, 2 press = 1 hour, 3 = 1 day unsigned long blankSuppressedMillis = 0; // The end time of the blanking, 0 if we are not suppressed unsigned long blankSuppressedSelectionTimoutMillis = 0; // Used for determining the end of the blanking period selection timeout boolean hourMode = false; boolean triggeredThisSec = false; byte useRTC = true; // true if we detect an RTC //now use - true byte useWiFi = 0; // the number of minutes ago we recevied information from the WiFi module, 0 = don't use WiFi byte cycleCount = 0; byte cycleSpeed = CYCLE_SPEED_DEFAULT; //byte Currentday; //DateTime now = RTC.now(); Currentday = now.day(); // RTClib not use - now DS3231 //if(Currentday == Startday){ int impressionsPerSec = 0; //loop time (20 per second now - delay 50 added) int lastImpressionsPerSec = 0; // ********************** Input switch management ********************** ClockButton button1(inputPin1, false); // one button // **************************** digit healing **************************** // This is a special mode which repairs cathode poisoning by driving a // single element at full power. To be used with care! // In theory, this should not be necessary because we have ACP every 10mins, // but some tubes just want to be poisoned byte digitBurnDigit = 0; byte digitBurnValue = 0; /* // create an array that translates decimal numbers into an appropriate byte for sending to the shift register int charTable[] = {0,128,64,192,32,160,96,224,16,144,8,136,72,200,40,168,104,232,24,152,4,132,68,196,36,164,100,228,20,148,12,140,76,204,44, 172,108,236,28,156,2,130,66,194,34,162,98,226, 18,146,10,138,74,202,42,170,106,234,26,154,6,134,70,198,38,166,102,230,22,150,14,142,78,206,46,174,110,238,30,158,1,129, 65,193,33,161,97,225,17,145,9,137,73,201,41,169,105,233,25,153}; */ byte nixies = 255; //initiate the byte to be sent to the shift register and set it to blank the nixies int x; //create a counting variable byte secondes = 86; //byte byte minutes = 79; //byte byte hours = 78; // ********************************************************************************** // ********************************************************************************** // * Setup * // ********************************************************************************** // ********************************************************************************** void setup(){ Wire.begin(); // init twowire sda scl pins A4 A5 - just connect 2 LED from 5v 300 Ohm resistor - see how works if (Serial) debug=true; if (debug)Serial.begin(57600); //de bug to serial Monitor port - in the right corner - press ctrl -m - serial speed 57000 pinMode(SER_Pin, OUTPUT); pinMode(RCLK_Pin, OUTPUT); pinMode(SRCLK_Pin, OUTPUT); // Grounding the input pin causes it to actuate pinMode(inputPin1, INPUT_PULLUP ); // set the input pin 1 // add resistor // вернул настройку HV и сброс до заводских настроек (нажать кнопку при включении) /* disable global interrupts while we set up them up */ cli(); // **************************** HV generator **************************** TCCR1A = 0; // disable all PWM on Timer1 whilst we set it up TCCR1B = 0; // disable all PWM on Timer1 whilst we set it up // Configure timer 1 for Fast PWM mode via ICR1, with prescaling=1 TCCR1A = (1 << WGM11); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); tccrOff = TCCR1A; TCCR1A |= (1 << COM1A1); // enable PWM on port PD4 in non-inverted compare mode 2 tccrOn = TCCR1A; // Set up timer 2 like timer 0 (for RGB leds) TCCR2A = (1 << COM2B1) | (1 << WGM21) | (1 << WGM20); TCCR2B = (1 << CS22); // we don't need the HV yet, so turn it off TCCR1A = tccrOff; /* enable global interrupts */ sei(); // ********************************************************************** // Set up the PRNG with something so that it looks random randomSeed(analogRead(LDRPin)); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } // User requested factory reset if (button1.isButtonPressedNow()) { // do this before the flashing, because this way we can set up the EEPROM to // autocalibrate on first start (press factory reset and then power off before // flashing ends) EEPROM.write(EE_HVG_NEED_CALIB, true); // Flash some ramdom c0lours to signal that we have accepted the factory reset /* for (int i = 0 ; i < 60 ; i++ ) { randomRGBFlash(20); } */ // mark that we need the EEPROM setup EEPROM.write(EE_NEED_SETUP, true); } // If the button is held down while we are flashing, then do the test pattern boolean doTestPattern = false; // Detect factory reset: button pressed on start or uninitialised EEPROM if (EEPROM.read(EE_NEED_SETUP)) { doTestPattern = true; } // Clear down any spurious button action button1.reset(); // Test if the button is pressed for factory reset for (int i = 0 ; i < 20 ; i++ ) { button1.checkButton(nowMillis); } if (button1.isButtonPressedNow()) { doTestPattern = true; } if (debug) Serial.println("Vklu4ilsja i'M Citten Lynx"); // comment - first run // factoryReset(); EEPROM.write(EE_FADE_STEPS, fadeSteps); //46 default or 42 blankLeading =1; fadeSteps=3; // Read EEPROM values (test - reads! -2 lines below) readEEPROMValues(); if (debug) { Serial.print("eeprom internal read 2 byte blankLeading fadeSteps - "); Serial.print(blankLeading); Serial.print(" ");//test what reads Serial.println(fadeSteps); //test what reads } // fadeSteps=49; // for test now 52 // 46 big cycles per second *1000 display timer 46000 установок регистров в секунду, а если 2 цифры сразу то 100000 (fade) // initialise the internal time (in case we don't find the time provider) первая установка времени здесь //1-st try getRTCTime(); // try to autodetect // Startday = now.day(); // de-bug - rtc ds3231 works - uncomment line run? comment line - run again //(comment - after first run) setTime(2, 48, 47, 5, 6, 2021); // ! и оно работает 16 37 36 через 3 минуты Works - manual set time // de-bug - rtc ds3231 works - uncomment line run? comment line - run again !! works!! time read OK from DS3231 chip useRTC = true; // autodetect near DateTime compiled = DateTime(__DATE__, __TIME__); //set time by current (DateTime compiled or manual) run once - comment line byte dayOfWeek= weekday(); //3 // 0- sunday воскресенье установка первый раз - вручную !! 1 раз после настройки // setDS3231time(second(), minute(), hour(), dayOfWeek, day(), month(), year()); // установка часов DS3231 по времени компьютера // setRTC(); //ok works - 1-st run /* Clock.setMinute(24);//Set the minute Clock.setHour(19); //Set the hour Clock.setDoW(5); //Set the day of the week Clock.setDate(4); //Set the date of the month Clock.setMonth(6); //Set the month of the year Clock.setYear(21); //Set the year (Last two digits of the year) Clock.setSecond(50);//Set the second - last - start clock // ok 1-st run set time */ // useRTC = false; byte year2digit=year() -2000; //setDS3231time(second(), minute(), hour(), dayOfWeek, dayOfMonth, decToBcd1(month()), decToBcd1(year())); if (debug){ Serial.print("setup now read from ds32321 - "); Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" year "); Serial.print(year2digit); Serial.print("-"); Serial.print(month()); Serial.print("-"); Serial.print(day()); Serial.print("-doW-"); Serial.println(dayOfWeek); } /* // установка значений времени (попытка) achtung // achtung this routine works - arduino set time into Maxim DS3231 (vcc=5, vbat=3 - 2 diodes, sda pin 15 to arduino nano A4, scl 16 - A5, R pullup 5k6 , R reset pin pull up 100k) dayOfWeek= Clock.getDoW(); // get or set Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(zero); //stop Oscillator // bool oscillatorCheck();; // Clock.setDoW(dayOfWeek); Clock.setMinute(minute()); Clock.setHour(hour()); Clock.setDoW(dayOfWeek); Clock.setDate(day()); Clock.setMonth(month()); Clock.setYear(year2digit); Clock.setClockMode(false); //24h Clock.enableOscillator(true, true, 0); Clock.setSecond(second()); //enable OSC clear flag */ bool PM; bool twentyFourHourClock; bool century = false; int years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); // setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // если зависает то смотреть монитор порта и закомментировать строку ниже i found what may hung up if (useRTC) getRTCTime(); if (debug){ Serial.print("verify ds32321 - "); Serial.print(hours); Serial.print(":"); Serial.print(mins); Serial.print(":"); Serial.print(secs); Serial.print(" year "); Serial.print(years); Serial.print("-"); Serial.print(months); Serial.print("-"); Serial.println(days); } if (doTestPattern) { boolean oldUseLDR = useLDR; // byte oldBacklightMode = backlightMode; // reset the EEPROM values factoryReset(); // turn off LDR useLDR = false; // turn off Scrollback scrollback = false; // All the digits on full allBright(); int secCount = 0; lastCheckMillis = millis(); boolean inLoop = true; // We don't want to stay in test mode forever long startTestMode = lastCheckMillis; while (inLoop) { nowMillis = millis(); if (nowMillis - lastCheckMillis > 1000) { lastCheckMillis = nowMillis; secCount++; secCount = secCount % 10; } // turn off test mode blankTubes = (nowMillis - startTestMode > TEST_MODE_MAX_MS); loadNumberArraySameValue(secCount); outputDisplay(); // checkHVVoltage(); // setLedsTestPattern(nowMillis); button1.checkButton(nowMillis); if (button1.isButtonPressedNow() && (secCount == 8)) { inLoop = false; blankTubes = false; } } useLDR = oldUseLDR; // backlightMode = oldBacklightMode; } /* debug eeprom values 0 50 2 0 100 0 0 0 4 700 100 1 0 7 100 0 1000 2 1 1 eeprom internal read 2 byte blankLeading fadeSteps - 0 50 setup now read from ds3232 1 - 12:56:47 year 21-6-3-doW-5 verify ds32321 - 12:56:47 year 2021-6-3 12:56:47 flag rtc 1-3-t-45.84-30.75 DS3231_T_1-st-byte=30 12:57:00 3 6 2021 20 DS3231_T-2byte=30.192 F 45.50 DS3231_T=30.75 */ // time rtc set OK /* void setSecond(byte Second); //ds3231 lib readme Eric Ayars // In addition to setting the seconds, this clears the // "Oscillator Stop Flag". void setMinute(byte Minute); // Sets the minute void setHour(byte Hour); // Sets the hour void setDoW(byte DoW); // Sets the Day of the Week (1-7); void setDate(byte Date); // Sets the Date of the Month void setMonth(byte Month); // Sets the Month of the year void setYear(byte Year); // Last two digits of the year void setClockMode(bool h12); // Set 12/24h mode. True is 12-h, false is 24-hour. // Temperature function float getTemperature(); // another RTC lib #include <RTClib.h> // Date, Time and Alarm functions by https://github.com/MrAlvin/RTClib //AT24C32 I2C eeprom //****************** #define EEPROM_ADDRESS 0x57 // I2C Buss address of AT24C32 32K EEPROM (first block) #define EEPromPageSize 32 // 32 bytes is page size for the AT24C32 unsigned int CurrentPageStartAddress = 0; // set to zero at the start of each cycle char EEPROMBuffer[28]; // this buffer contains a string of ascii because I am using the pstring function to load it uint8_t BytesWrittentoSD = 0; //DS3231 RTC //********** #define DS3231_ADDRESS 0x68 //=104 dec #define DS3231_STATUS_REG 0x0f #define DS3231_CTRL_REG 0x0e #define Bit0_MASK B00000001 //Bit 0=Alarm 1 Flag (A1F) #define Bit1_MASK B00000010 //Bit 1 = Alarm 2 Flag (A2F) #define Bit2_MASK B00000100 #define Bit3_MASK B00001000 //Bit 3: Enable/disable 32kHz Output (EN32kHz) - has no effect on sleep current #define Bit4_MASK B00010000 //Bit 4: Bits 4&5 of status reg adjust Time Between Temperature Updates see http://www.maximintegrated.com/en/app-notes/index.mvp/id/3644 #define Bit5_MASK B00100000 //Bit 5: #define Bit6_MASK B01000000 #define Bit7_MASK B10000000 #define RTCPOWER_PIN 7 //When the arduino is awake, power the rtc from this pin (draws ~70uA), when arduino sleeps pin set low & rtc runs on battery at <3uA // SEE http://www.gammon.com.au/forum/?id=11497 for an example powering ds1307 from pin, alarms still work! RTC_DS3231 RTC; //DS3231 will function with a VCC ranging from 2.3V to 5.5V byte Alarmhour = 1; byte Alarmminute = 1; byte Alarmday = 1; //only used for sub second alarms byte Alarmsecond = 1; //only used for sub second alarms byte INTERRUPT_PIN = 2; // SQW is soldered to this pin on the arduino volatile boolean clockInterrupt = false; char CycleTimeStamp[ ]= "0000/00/00,00:00"; //16 characters without seconds! byte Startday; Serial.begin(9600); Wire.begin(); RTC.begin(); // check RTC //another library //********** clearClockTrigger(); //stops RTC from holding the interrupt low if system reset just occured RTC.turnOffAlarm(1); i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,0,Bit3_MASK); // disable the 32khz output pg14-17 of datasheet //This does not reduce the sleep current i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK); // see APPLICATION NOTE 3644 - this might only work on the DS3234? i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK); // setting bits 4&5 to 1, extends the time between RTC temp updates to 512seconds (from default of 64s) DateTime now = RTC.now(); Startday = now.day(); DateTime compiled = DateTime(__DATE__, __TIME__); if (now.unixtime() < compiled.unixtime()) { //checks if the RTC is not set yet Serial.println(F("RTC is older than compile time! Updating")); // following line sets the RTC to the date & time this sketch was compiled RTC.adjust(DateTime(__DATE__, __TIME__)); Serial.println(F("Clock updated....")); DateTime now = RTC.now(); Startday = now.day(); //get the current day for the error routine } */ // getRTCTime(); //comment if stop responding float c = Clock.getTemperature(); float f = c / 4. * 9. / 5. + 32.; // Fahrenheit if (debug){ Serial.print(hour()); Serial.print(":"); Serial.print(minute()); Serial.print(":"); Serial.print(second()); Serial.print(" flag rtc "); Serial.print(useRTC); Serial.print("-"); Serial.print(Clock.getDate()); Serial.print("-t-"); Serial.print(f); Serial.print("-"); Serial.println(c); } // Clear down any spurious button action button1.reset(); // initialise the internal time (in case we don't find the time provider) nowMillis = millis(); // setTime(12, 34, 56, 1, 3, 2017); // getRTCTime(); // Show the version for 1 s tempDisplayMode = TEMP_MODE_VERSION; tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; // don't blank anything right now blanked = false; setTubesAndLEDSBlankMode(); // mark that we have done the EEPROM setup EEPROM.write(EE_NEED_SETUP, false); // enable watchdog wdt_enable(WDTO_8S); } void loop(){ nowMillis = millis(); // shows us how fast the inner loop is running impressionsPerSec++; if (abs(nowMillis - lastCheckMillis) >= 1000) { if ((second() == 0) && (!triggeredThisSec)) { if ((minute() == 0)) { if (hour() == 0) { // performOncePerDayProcessing(); } performOncePerHourProcessing(); } performOncePerMinuteProcessing(); } performOncePerSecondProcessing(); // Make sure we don't call multiple times triggeredThisSec = true; if ((second() > 0) && triggeredThisSec) { triggeredThisSec = false; } lastCheckMillis = nowMillis; } // byte second, minute, hour; // shifter.setAll(HIGH); //minutes = 77; //hours = 77; // time for cycle (impressions) //delay(50); // // Check button, we evaluate below button1.checkButton(nowMillis); // ******* Preview the next display mode ******* // What is previewed here will get actioned when // the button is released if (button1.isButtonPressed2S()) { if (debug){ Serial.println(" butt 2s "); } // Just jump back to the start nextMode = MODE_MIN; } else if (button1.isButtonPressed1S()) { nextMode = currentMode + 1; if (debug){ Serial.println(" butt 1s "); } if (nextMode > MODE_MAX) { nextMode = MODE_MIN; } } // ******* Set the display mode ******* if (button1.isButtonPressedReleased8S()) { // 8 Sec press toggles burn mode if (currentMode == MODE_DIGIT_BURN) { currentMode = MODE_MIN; } else { currentMode = MODE_DIGIT_BURN; } nextMode = currentMode; } else if (button1.isButtonPressedReleased2S()) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); nextMode = currentMode; } else if (button1.isButtonPressedReleased1S()) { if (debug){ Serial.println(" button 1s p-r "); } currentMode = nextMode; if (currentMode > MODE_MAX) { currentMode = MODE_MIN; // Store the EEPROM if we exit the config mode saveEEPROMValues(); // Preset the display allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } nextMode = currentMode; } // ------------------------------------------------------------------------------- // ************* Process the modes ************* if (nextMode != currentMode) { setNextMode(nextMode); } else { processCurrentMode(currentMode); } // get the LDR ambient light reading digitOffCount = getDimmingFromLDR(); // 120 dark (night) 999 bright - day fadeStep = digitOffCount / fadeSteps; // 3 -dark ... 20 bright // One armed bandit trigger every 10th minute if ((currentMode != MODE_DIGIT_BURN) && (nextMode != MODE_DIGIT_BURN)) { if (acpOffset == 0) { if (((minute() % 10) == 9) && (second() == 15)) { // suppress ACP when fully dimmed if (suppressACP) { if (digitOffCount > minDim) { acpOffset = 0; // 0 - не дергаю однорукого бандита acp off } } else { acpOffset = 1; // 0 ? 1 is anti poison on // effects at 15 +50 seconds - do anti-poison too } } } // One armed bandit handling if (acpOffset > 0) { if (acpTick >= acpOffset) { acpTick = 0; acpOffset++; if (acpOffset == 7) { acpOffset = 0; } } else { acpTick++; } } // Set normal output display outputDisplay(); } else { // Digit burn mode // Santosha - turn on digit using Shifter // but useless - current set as normal light // dynamic mode - max bright OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; OnOff[digitBurnDigit] =1; // digitOn(digitBurnDigit, digitBurnValue,10,10,10,10,10,10); digitOn(digitBurnDigit, digitBurnValue); } // ------------------------------------------------------------------------------- // Prepare the tick and backlight LEDs //setLeds(); } //main loop xwost tail // modes - set time or display clock (press button for 1 s) // ************************************************************ // Show the preview of the next mode - we stay in this mode until the // button is released // ************************************************************ void setNextMode(int displayMode) { // turn off blanking blanked = false; setTubesAndLEDSBlankMode(); switch (displayMode) { case MODE_TIME: { loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); break; } case MODE_HOURS_SET: { if (useWiFi > 0) { setNewNextMode(MODE_12_24); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_MINS_SET: { loadNumberArrayTime(); highlight2and3(); break; } case MODE_SECS_SET: { loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if ((dayBlanking == DAY_BLANKING_NEVER) || (dayBlanking == DAY_BLANKING_WEEKEND) || (dayBlanking == DAY_BLANKING_WEEKDAY) || (dayBlanking == DAY_BLANKING_ALWAYS)) { // Skip past the start and end hour if the blanking mode says it is not relevant setNewNextMode(MODE_SUPPRESS_ACP); } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_USE_LDR: { loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: case MODE_FADE_STEPS_DOWN: { loadNumberArrayConfInt(fadeSteps, displayMode); //50 .. 45 not more than 1 second = 46 // 49 cycles displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: case MODE_DISPLAY_SCROLL_STEPS_DOWN: { loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: case MODE_MIN_DIM_DOWN: { loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_ANTI_GHOST_UP: case MODE_ANTI_GHOST_DOWN: { loadNumberArrayConfInt(antiGhost, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { loadNumberArrayTestDigits(); allNormal(); break; } case MODE_DIGIT_BURN: { // Nothing: handled separately to suppress multiplexing } } } // ************************************************************ // Show the next mode - once the button is released // ************************************************************ void processCurrentMode(int displayMode) { switch (displayMode) { case MODE_TIME: { if (button1.isButtonPressedAndReleased()) { // Deal with blanking first if ((nowMillis < blankSuppressedSelectionTimoutMillis) || blanked) { if (blankSuppressedSelectionTimoutMillis == 0) { // Apply 5 sec tineout for setting the suppression time blankSuppressedSelectionTimoutMillis = nowMillis + TEMP_DISPLAY_MODE_DUR_MS; } blankSuppressStep++; if (blankSuppressStep > 3) { blankSuppressStep = 3; } if (blankSuppressStep == 1) { blankSuppressedMillis = 10000; } else if (blankSuppressStep == 2) { blankSuppressedMillis = 3600000; } else if (blankSuppressStep == 3) { blankSuppressedMillis = 3600000 * 4; } blanked = false; setTubesAndLEDSBlankMode(); } else { // Always start from the first mode, or increment the temp mode if we are already in a display if (tempDisplayModeDuration > 0) { tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; tempDisplayMode++; } else { tempDisplayMode = TEMP_MODE_MIN; } if (tempDisplayMode > TEMP_MODE_MAX) { tempDisplayMode = TEMP_MODE_MIN; } tempDisplayModeDuration = TEMP_DISPLAY_MODE_DUR_MS; } } if (second() == 15) { // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } if (tempDisplayModeDuration > 0) { blanked = false; setTubesAndLEDSBlankMode(); if (tempDisplayMode == TEMP_MODE_DATE) { loadNumberArrayDate(); } if (tempDisplayMode == TEMP_MODE_TEMP) { byte timeProv = 10; if (useRTC) timeProv += 1; if (useWiFi > 0) timeProv += 2; loadNumberArrayTemp(timeProv); } if (tempDisplayMode == TEMP_MODE_LDR) { loadNumberArrayLDR(); } if (tempDisplayMode == TEMP_IP_ADDR12) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[0], ourIP[1]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IP_ADDR34) { if (useWiFi > 0) { loadNumberArrayIP(ourIP[2], ourIP[3]); } else { // we can't show the IP address if we have the RTC, just skip tempDisplayMode++; } } if (tempDisplayMode == TEMP_IMPR) { loadNumberArrayConfInt(lastImpressionsPerSec, 0); } allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } else { if (acpOffset > 0) { loadNumberArrayACP(); allBright(); } else { if (slotsMode > SLOTS_MODE_MIN) { if (second() == 50) { // initialise the slots values loadNumberArrayDate(); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); transition.start(nowMillis); } // initialise the slots mode boolean msgDisplaying; switch (slotsMode) { case SLOTS_MODE_1M_SCR_SCR: { msgDisplaying = transition.scrollInScrambleOut(nowMillis); break; } } // Continue slots if (msgDisplaying) { transition.updateRegularDisplaySeconds(second()); } else { // do normal time thing when we are not in slots loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } else { // no slots mode, just do normal time thing loadNumberArrayTime(); allFadeOrNormal(APPLY_LEAD_0_BLANK); } } } break; } case MODE_MINS_SET: { if (button1.isButtonPressedAndReleased()) { incMins(); } loadNumberArrayTime(); highlight2and3(); break; } case MODE_HOURS_SET: { if (button1.isButtonPressedAndReleased()) { incHours(); } loadNumberArrayTime(); highlight0and1(); break; } case MODE_SECS_SET: { if (button1.isButtonPressedAndReleased()) { resetSecond(); } loadNumberArrayTime(); highlight4and5(); break; } case MODE_DAYS_SET: { if (button1.isButtonPressedAndReleased()) { incDays(); } loadNumberArrayDate(); highlightDaysDateFormat(); break; } case MODE_MONTHS_SET: { if (button1.isButtonPressedAndReleased()) { incMonths(); } loadNumberArrayDate(); highlightMonthsDateFormat(); break; } case MODE_YEARS_SET: { if (button1.isButtonPressedAndReleased()) { incYears(); } loadNumberArrayDate(); highlightYearsDateFormat(); break; } case MODE_12_24: { if (button1.isButtonPressedAndReleased()) { hourMode = ! hourMode; } loadNumberArrayConfBool(hourMode, displayMode); displayConfig(); break; } case MODE_LEAD_BLANK: { if (button1.isButtonPressedAndReleased()) { blankLeading = !blankLeading; } loadNumberArrayConfBool(blankLeading, displayMode); displayConfig(); break; } case MODE_SCROLLBACK: { if (button1.isButtonPressedAndReleased()) { scrollback = !scrollback; } loadNumberArrayConfBool(scrollback, displayMode); displayConfig(); break; } case MODE_FADE: { if (button1.isButtonPressedAndReleased()) { fade = !fade; } loadNumberArrayConfBool(fade, displayMode); displayConfig(); break; } case MODE_DATE_FORMAT: { if (button1.isButtonPressedAndReleased()) { dateFormat++; if (dateFormat > DATE_FORMAT_MAX) { dateFormat = DATE_FORMAT_MIN; } } loadNumberArrayConfInt(dateFormat, displayMode); displayConfig(); break; } case MODE_DAY_BLANKING: { if (button1.isButtonPressedAndReleased()) { dayBlanking++; if (dayBlanking > DAY_BLANKING_MAX) { dayBlanking = DAY_BLANKING_MIN; } } loadNumberArrayConfInt(dayBlanking, displayMode); displayConfig(); break; } case MODE_HR_BLNK_START: { if (button1.isButtonPressedAndReleased()) { blankHourStart++; if (blankHourStart > HOURS_MAX) { blankHourStart = 0; } } loadNumberArrayConfInt(blankHourStart, displayMode); displayConfig(); break; } case MODE_HR_BLNK_END: { if (button1.isButtonPressedAndReleased()) { blankHourEnd++; if (blankHourEnd > HOURS_MAX) { blankHourEnd = 0; } } loadNumberArrayConfInt(blankHourEnd, displayMode); displayConfig(); break; } case MODE_SUPPRESS_ACP: { if (button1.isButtonPressedAndReleased()) { suppressACP = !suppressACP; } loadNumberArrayConfBool(suppressACP, displayMode); displayConfig(); break; } case MODE_BLANK_MODE: { if (button1.isButtonPressedAndReleased()) { blankMode++; if (blankMode > BLANK_MODE_MAX) { blankMode = BLANK_MODE_MIN; } } loadNumberArrayConfInt(blankMode, displayMode); displayConfig(); break; } case MODE_USE_LDR: { if (button1.isButtonPressedAndReleased()) { useLDR = !useLDR; } loadNumberArrayConfBool(useLDR, displayMode); displayConfig(); break; } case MODE_FADE_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { fadeSteps++; if (fadeSteps > FADE_STEPS_MAX) { fadeSteps = FADE_STEPS_MIN; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); // fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; // if bright 1000 = 100% 1000 /50 =20 fadeStep = digitOffCount / fadeSteps; // if night dimming may be 2 -3 timer tick ' one bright step' break; } case MODE_FADE_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { fadeSteps--; if (fadeSteps < FADE_STEPS_MIN) { fadeSteps = FADE_STEPS_MAX; } } loadNumberArrayConfInt(fadeSteps, displayMode); displayConfig(); // fadeStep = DIGIT_DISPLAY_COUNT / fadeSteps; fadeStep = digitOffCount / fadeSteps; // time diagram .. 1000 /45.. 46 =~ 20 ticks - 'timer' one brightness step - if max dimming - ~~3 ..4 break; } case MODE_DISPLAY_SCROLL_STEPS_DOWN: { if (button1.isButtonPressedAndReleased()) { scrollSteps--; if (scrollSteps < SCROLL_STEPS_MIN) { scrollSteps = SCROLL_STEPS_MAX; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_DISPLAY_SCROLL_STEPS_UP: { if (button1.isButtonPressedAndReleased()) { scrollSteps++; if (scrollSteps > SCROLL_STEPS_MAX) { scrollSteps = SCROLL_STEPS_MIN; } } loadNumberArrayConfInt(scrollSteps, displayMode); displayConfig(); break; } case MODE_SLOTS_MODE: { if (button1.isButtonPressedAndReleased()) { slotsMode++; if (slotsMode > SLOTS_MODE_MAX) { slotsMode = SLOTS_MODE_MIN; } } loadNumberArrayConfInt(slotsMode, displayMode); displayConfig(); break; } case MODE_MIN_DIM_UP: { if (button1.isButtonPressedAndReleased()) { minDim += 10; if (minDim > MIN_DIM_MAX) { minDim = MIN_DIM_MAX; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_MIN_DIM_DOWN: { if (button1.isButtonPressedAndReleased()) { minDim -= 10; if (minDim < MIN_DIM_MIN) { minDim = MIN_DIM_MIN; } } loadNumberArrayConfInt(minDim, displayMode); displayConfig(); break; } case MODE_TEMP: { loadNumberArrayTemp(displayMode); displayConfig(); break; } case MODE_TUBE_TEST: { allNormal(); loadNumberArrayTestDigits(); break; } case MODE_DIGIT_BURN: { if (button1.isButtonPressedAndReleased()) { digitBurnValue += 1; if (digitBurnValue > 9) { digitBurnValue = 0; digitOff(0); digitBurnDigit += 1; if (digitBurnDigit > 5) { digitBurnDigit = 0; } } } } } } /* //********************************************************************************** //********************************************************************************** //* High Voltage generator * //********************************************************************************** //********************************************************************************** // ************************************************************ // Adjust the HV gen to achieve the voltage we require // Pre-calculate the threshold value of the ADC read and make // a simple comparison against this for speed // We control only the PWM "off" time, because the "on" time // affects the current consumption and MOSFET heating // ************************************************************ void checkHVVoltage() { if (getSmoothedHVSensorReading() > rawHVADCThreshold) { setPWMTopTime(pwmTop + getInc()); } else { setPWMTopTime(pwmTop - getInc()); } } // Get the increment value we are going to use based on the magnitude of the // difference we have measured int getInc() { int diffValue = abs(getSmoothedHVSensorReading() - rawHVADCThreshold); int incValue = 1; if (diffValue > 20) incValue = 50; else if (diffValue > 10) incValue = 5; return incValue; } // ************************************************************ // Calculate the target value for the ADC reading to get the // defined voltage // ************************************************************ int getRawHVADCThreshold(double targetVoltage) { double externalVoltage = targetVoltage * 4.7 / 394.7 * 1023 / 5; int rawReading = (int) externalVoltage; return rawReading; } */ // ********************************************************************************** // ********************************************************************************** // * Light Dependent Resistor * // ********************************************************************************** // ********************************************************************************** // ****************************************************************** // Check the ambient light through the LDR (Light Dependent Resistor) // Smooths the reading over several reads. // // The LDR in bright light gives reading of around 50, the reading in // total darkness is around 900. // // The return value is the dimming count we are using. 999 is full // brightness, 100 is very dim. // // Because the floating point calculation may return more than the // maximum value, we have to clamp it as the final step // ****************************************************************** int getDimmingFromLDR() { if (useLDR) { int rawSensorVal = 1023 - analogRead(LDRPin); double sensorDiff = rawSensorVal - sensorLDRSmoothed; sensorLDRSmoothed += (sensorDiff / sensorSmoothCountLDR); double sensorSmoothedResult = sensorLDRSmoothed - dimDark; if (sensorSmoothedResult < dimDark) sensorSmoothedResult = dimDark; if (sensorSmoothedResult > dimBright) sensorSmoothedResult = dimBright; // no ldr but useLDR true (test) =dimBright (999) // фоторезистор - если не запаян то установить значение на полную яркость sensorSmoothedResult = dimDark +1; //sensorSmoothedResult = dimBright; sensorSmoothedResult = (sensorSmoothedResult - dimDark) * sensorFactor; int returnValue = sensorSmoothedResult; if (returnValue < minDim) returnValue = minDim; if (returnValue > DIGIT_DISPLAY_OFF) returnValue = DIGIT_DISPLAY_OFF; return returnValue; } else { return DIGIT_DISPLAY_OFF; } } /* /*void doTest() { Serial.print(F("test version: ")); // Serial.println(FirmwareVersion.substring(1,2)+"."+FirmwareVersion.substring(2,5)); // for (byte k = 0; k < strlen_P(HardwareVersion); k++) { // Serial.print((char)pgm_read_byte_near(HardwareVersion + k)); // } // Serial.println(); Serial.println(F("Start Test")); // p=song; // parseSong(p); //p=0; //need to be deleted // LEDsTest(); #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) if (Serial1.available() > 10) Serial.println(F("GPS detected")); else Serial.println(F("GPS NOT detected!")); #endif // #ifdef tubes8 // String testStringArray[11]={"00000000","11111111","22222222","33333333","44444444","55555555","66666666","77777777","88888888","99999999",""}; // testStringArray[10]=FirmwareVersion+"00"; // #endif // #ifdef tubes6 String testStringArray[11]={"000000","111111","222222","333333","444444","555555","666666","777777","888888","999999",""}; testStringArray[10]="123"; // #endif int dlay=500; bool test=1; byte strIndex=-1; unsigned long startOfTest=millis()+1000; //disable delaying in first iteration bool digitsLock=false; while (test) { // if (digitalRead(pinDown)==0) digitsLock=true; // if (digitalRead(pinUp)==0) digitsLock=false; if ((millis()-startOfTest)>dlay) { startOfTest=millis(); if (!digitsLock) strIndex=strIndex+1; if (strIndex==10) dlay=2000; if (strIndex>10) { test=false; strIndex=10;} Serial.println(testStringArray[strIndex]); // doIndication(); } delayMicroseconds(2000); }; // if ( !ds.search(addr)) // { // Serial.println(F("Temp. sensor not found.")); // } else TempPresent=true; Serial.println(F("Stop Test")); // while(1); } */ void doDotBlink() { byte dotPattern = B00000000; if (second()%2 == 0) dotPattern = B11000000; else dotPattern = B00000000; } // ************************************************************ // Called once per second // ************************************************************ void performOncePerSecondProcessing() { // Store the current value and reset lastImpressionsPerSec = impressionsPerSec; impressionsPerSec = 0; threesectimer= threesectimer+1 ; if (threesectimer==3) { threesectimer=0; int digitSwitchTime[6]= {-1, -1, -1, -1, -1, -1}; //clear fade effect each 3 seconds //was 3-4 digit turn on at one time in 2 -3 tubes tens - ones seconds //byte currNumberArray[6] = {10, 10, 10, 10, 10, 10}; // byte OnOff[6] = {0, 0, 0, 0, 0, 0}; byte fadeState[6] = {0, 0, 0, 0, 0, 0}; // initialise the slots values temperature loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); // transition.start(nowMillis); // убрал - моргает /* digitOff(5); digitOff(4); digitOff(3); digitOff(2); digitOff(1); digitOff(0); */ } for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { currNumberArray[i] = NumberArray[i]; // clear Fade if over-run } // Change the direction of the pulse // upOrDown = !upOrDown; // If we are in temp display mode, decrement the count if (tempDisplayModeDuration > 0) { if (tempDisplayModeDuration > 1000) { tempDisplayModeDuration -= 1000; } else { tempDisplayModeDuration = 0; } } // decrement the blanking supression counter if (blankSuppressedMillis > 0) { if (blankSuppressedMillis > 1000) { blankSuppressedMillis -= 1000; } else { blankSuppressedMillis = 0; } } // Get the blanking status, this may be overridden by blanking suppression // Only blank if we are in TIME mode if (currentMode == MODE_TIME) { boolean nativeBlanked = checkBlanking(); // Check if we are in blanking suppression mode blanked = nativeBlanked && (blankSuppressedMillis == 0); // reset the blanking period selection timer if (nowMillis > blankSuppressedSelectionTimoutMillis) { blankSuppressedSelectionTimoutMillis = 0; blankSuppressStep = 0; } } else { blanked = false; } setTubesAndLEDSBlankMode(); // Slow regulation of the voltage //checkHVVoltage(); // feed the watchdog wdt_reset(); // getRTCTime(); //перегорит через неделю или сядет батарейка - включить батарейку через 2 диодика // byte secondes = second(); //byte minutes = minute(); //byte hours = hour() ; // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // loadNumberArrayTime(); // do complete display (this was test) // display_nixietubes(); // display the real-time clock data on the Nixies set data //change to NumberArray as in the original code - display different data // shifter.write(); } // ************************************************************ // Called once per minute // ************************************************************ void performOncePerMinuteProcessing() { // digitalClockDisplay() ; //print time - digits as hh:mm:ss to serial port 57600 if (debug)Serial.print(lastImpressionsPerSec); // cycles per second - delay 50 show 20 cycles if (debug)Serial.println(); /* nixietrainer(); // anti cathodes poisoning 1.8sec all // if (debug){ if (useRTC) testDS3231TempSensor(); //display temperature // } */ //shifter.setAll(HIGH); // off all tubes // shifter.write(); //send changes to the chain and display them /* * время с ds3231 - раз в час поменял * allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); OnOff[0]=0; OnOff[1]=0; OnOff[2]=0; OnOff[3]=0; OnOff[4]=0; OnOff[5]=0; // initialise the slots values temperature // после чтения чипа часов есть ошибка - засветка третьей одновременно цифры нуля или единички на 4 лампах кроме часовых! loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); */ int digitSwitchTime[6]= {-1, -1, -1, -1, -1, -1}; // OK fade 2 digit together Works // заработал режим переключения с плавным гашением was glitch 3 digits together each minute.. } // ************************************************************ // Called once per hour // ************************************************************ void performOncePerHourProcessing() { // считывание ds3231 перенес на 1 раз в час .. глюк - сбивается режим fade .. не только - сбрасываю еще digitSwithcTime if (useWiFi > 0) { if (useWiFi == MAX_WIFI_TIME) { // We recently got an update, send to the RTC (if installed) setRTC(); } useWiFi--; } else { // get the time from the external RTC provider - (if installed) one time each minute перенес на каждый час if (useRTC) getRTCTime(); } // initialise the slots values temperature // после чтения чипа часов есть ошибка - засветка третьей одновременно цифры нуля или единички на 4 лампах кроме часовых! loadNumberArrayTemp(11); transition.setAlternateValues(); loadNumberArrayTime(); transition.setRegularValues(); allFadeOrNormal(DO_NOT_APPLY_LEAD_0_BLANK); } //subs /* // shiftout void updateShiftRegister(){ digitalWrite(RCLK_Pin, LOW); shiftOut(SER_Pin, SRCLK_Pin, LSBFIRST, nixies); digitalWrite(RCLK_Pin, HIGH); } */ void testDS3231TempSensor() { byte DS3231InternalTemperature=0; //another RTC Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(0x11); Wire.endTransmission(); Wire.requestFrom(RTC_I2C_ADDRESS, 2); DS3231InternalTemperature=Wire.read(); float c = DS3231InternalTemperature ; float f = c / 4. * 9. / 5. + 32.; DS3231InternalTemperature=Wire.read(); //fractial 2-nd byte if (debug) { Serial.print(F("DS3231_T-2byte=")); int wholeDegrees = int(c); Serial.print(wholeDegrees); Serial.print("."); Serial.print(int (DS3231InternalTemperature)); Serial.print(" F "); Serial.println(f); if ((c<2) || (c>95)) { Serial.println(F("wrong read DS3231!")); for (int i=0; i<5; i++) { //tone(pinBuzzer, 1000); // tone1.play(1000, 1000); // delay(2000); } } } float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); byte minutes = wholeDegrees; // Rus температура на 6 лампах - первые 2 гасятся, потом целая часть - градусы, потом дробная. byte secondes = fractDegrees; //byte hours = hour(); if (debug) { Serial.print(F("DS3231_T=")); Serial.print(wholeDegrees); Serial.print("."); Serial.println(fractDegrees); // DS3231_T=21.75 (Celsius) } // display_nixietubes(secondes, minutes, hours); // display the real-time clock data on the nixies //shifter.setAll(HIGH); prints(secondes); printm(minutes); shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); shifter.write(); //display temperature (2 -digit hours blank) delay(2000); } void display_nixietubes() { //void display_nixietubes(byte secondes, byte minutes, byte hours) //set data for display - 6 Nixie tubes with driver K155ID1 // change to display NumberArray //byte second, minute, hour; // shifter set pins of (3) or 4 registers 74hc595, then call shifter.write(); // retrieve data from DS3231 //readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // second = 81; //minute = 98; //hour = 69; //prints(secondes); //printm(minutes); //printh(hours); // prints nixie (20, NumberArray[5]); //seconds - lamp 5 -6 nixie (16, NumberArray[4]); // printm nixie (12, NumberArray[3]); nixie (8, NumberArray[2]); //minutes //printh nixie (4, NumberArray[1]); nixie (0, NumberArray[0]); //hours lamp 1-2 } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void digitalClockDisplay() { if (debug){ Serial.print(hour()); printDigits(minute()); // 12:35:00 time format (trranslate from Russian - printTime) +4 = 16:35 printDigits(second()); Serial.print(' '); Serial.print(day()); Serial.print(' '); Serial.print(month()); Serial.print(' '); Serial.print(year()); Serial.println(); } } void printDigits(int digits) { Serial.print(':'); if (digits < 10) Serial.print('0'); Serial.print(digits); } void nixietrainer() { int i=2; if (i> 0) { shifter.clear(); shifter.write(); prints(00); printm(00); printh(00); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(11); printm(11); printh(11); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(22); printm(22); printh(22); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(33); printm(33); printh(33); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(44); printm(44); printh(44); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(55); printm(55); printh(55); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(66); printm(66); printh(66); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(77); printm(77); printh(77); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(88); printm(88); printh(88); shifter.write(); delay(100); shifter.clear(); shifter.write(); prints(99); printm(99); printh(99); shifter.write(); delay(100); shifter.clear(); shifter.write(); i=i-1; } return; } void prints(int v) { int oness; int tenss; oness = v % 10; v = v / 10; tenss = v % 10; nixie (20, oness); nixie (16, tenss); } void printm(int m) { int onesm; int tensm; onesm = m % 10; m = m / 10; tensm = m % 10; nixie (12, onesm); nixie (8, tensm); } void printh(int h) { int onesh; int tensh; onesh = h % 10; h = h / 10; tensh = h % 10; nixie (4, onesh); nixie (0, tensh); } // ************************************************************ // Get the time from the RTC - rtc ds3231 + eeprom 24c32 - no module! solder to registers board // ************************************************************ void getRTCTime() { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //0x00 pointer - read from internal register 0 Wire.endTransmission(); // useRTC = (Wire.endTransmission() == 0); if (useRTC) { bool PM; bool twentyFourHourClock; bool century = false; //bool h12; byte years = Clock.getYear() + 2000; byte months = Clock.getMonth(century); byte days = Clock.getDate(); //byte hours = Clock.getHour(h12, PM); byte hours = Clock.getHour(twentyFourHourClock, PM); byte mins = Clock.getMinute(); byte secs = Clock.getSecond(); setTime(hours, mins, secs, days, months, years); // Make sure the clock keeps running even on battery if (!Clock.oscillatorCheck()) Clock.enableOscillator(true, true, 0); // or set seconds - start osc } // Return back to I2C in slave mode Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } // ************************************************************ // Set the date/time in the RTC from the internal time // Always hold the time in 24 format, we convert to 12 in the // display. // ************************************************************ void setRTC() { if (useRTC) { // Start the RTC communication in master mode Wire.end(); Wire.begin(); // Set up the time provider // first try to find the RTC, if not available, go into slave mode ?wifi module // rtc DS3231 vcc=5v vbat >3v Wire.beginTransmission(RTC_I2C_ADDRESS); Wire.write(zero); //stop Oscillator Clock.setClockMode(false); // false = 24h Clock.setYear(year() % 100); Clock.setMonth(month()); Clock.setDate(day()); Clock.setDoW(weekday()); Clock.setHour(hour()); Clock.setMinute(minute()); Clock.setSecond(second()); // start osc // Wire.write(zero); //start Wire.endTransmission(); Wire.end(); // Wire.begin(I2C_SLAVE_ADDR); // Wire.onReceive(receiveEvent); // Wire.onRequest(requestEvent); } } // ************************************************************ // Get the temperature from the RTC // ************************************************************ float getRTCTemp() { if (useRTC) { return Clock.getTemperature(); } else { return 0.0; } } //********************************************************************************** //********************************************************************************** //* EEPROM interface * //********************************************************************************** //********************************************************************************** // ************************************************************ // Save current values back to EEPROM // ************************************************************ void saveEEPROMValues() { EEPROM.write(EE_12_24, hourMode); EEPROM.write(EE_FADE_STEPS, fadeSteps); EEPROM.write(EE_DATE_FORMAT, dateFormat); EEPROM.write(EE_DAY_BLANKING, dayBlanking); EEPROM.write(EE_DIM_DARK_LO, dimDark % 256); EEPROM.write(EE_DIM_DARK_HI, dimDark / 256); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); EEPROM.write(EE_SCROLLBACK, scrollback); EEPROM.write(EE_FADE, fade); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); EEPROM.write(EE_DIM_BRIGHT_LO, dimBright % 256); EEPROM.write(EE_DIM_BRIGHT_HI, dimBright / 256); EEPROM.write(EE_DIM_SMOOTH_SPEED, sensorSmoothCountLDR); // EEPROM.write(EE_RED_INTENSITY, redCnl);// EEPROM.write(EE_GRN_INTENSITY, grnCnl);// EEPROM.write(EE_BLU_INTENSITY, bluCnl);// EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); // EEPROM.write(EE_HV_VOLTAGE, hvTargetVoltage); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); // EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); // EEPROM.write(EE_PULSE_LO, pwmOn % 256); // EEPROM.write(EE_PULSE_HI, pwmOn / 256); // EEPROM.write(EE_PWM_TOP_LO, pwmTop % 256); // EEPROM.write(EE_PWM_TOP_HI, pwmTop / 256); EEPROM.write(EE_MIN_DIM_LO, minDim % 256); EEPROM.write(EE_MIN_DIM_HI, minDim / 256); EEPROM.write(EE_ANTI_GHOST, antiGhost); EEPROM.write(EE_USE_LDR, useLDR); EEPROM.write(EE_BLANK_MODE, blankMode); EEPROM.write(EE_SLOTS_MODE, slotsMode); } // ************************************************************ // read EEPROM values // ************************************************************ void readEEPROMValues() { hourMode = EEPROM.read(EE_12_24); fadeSteps = EEPROM.read(EE_FADE_STEPS); if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } dateFormat = EEPROM.read(EE_DATE_FORMAT); dayBlanking = EEPROM.read(EE_DAY_BLANKING); dimDark = EEPROM.read(EE_DIM_DARK_HI) * 256 + EEPROM.read(EE_DIM_DARK_LO); if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } blankLeading = EEPROM.read(EE_BLANK_LEAD_ZERO); scrollback = EEPROM.read(EE_SCROLLBACK); fade = EEPROM.read(EE_FADE); scrollSteps = EEPROM.read(EE_SCROLL_STEPS); dimBright = EEPROM.read(EE_DIM_BRIGHT_HI) * 256 + EEPROM.read(EE_DIM_BRIGHT_LO); if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } sensorSmoothCountLDR = EEPROM.read(EE_DIM_SMOOTH_SPEED); if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } suppressACP = EEPROM.read(EE_SUPPRESS_ACP); blankHourStart = EEPROM.read(EE_HOUR_BLANK_START); if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } blankHourEnd = EEPROM.read(EE_HOUR_BLANK_END); if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } minDim = EEPROM.read(EE_MIN_DIM_HI) * 256 + EEPROM.read(EE_MIN_DIM_LO); if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } antiGhost = EEPROM.read(EE_ANTI_GHOST); dispCount = DIGIT_DISPLAY_COUNT + antiGhost; blankMode= EEPROM.read(EE_BLANK_MODE); useLDR = EEPROM.read(EE_USE_LDR); slotsMode= EEPROM.read(EE_SLOTS_MODE); if (debug){ Serial.print(hourMode); Serial.print(' '); Serial.print(fadeSteps); Serial.print(' '); Serial.print(dateFormat); Serial.print(' '); Serial.print(dayBlanking); Serial.print(' '); Serial.print(dimDark); Serial.print(' '); Serial.print(blankLeading); Serial.print(' '); Serial.print(scrollback); Serial.println(); Serial.print(fade); Serial.print(' '); Serial.print(scrollSteps); Serial.print(' '); Serial.print(dimBright); Serial.print(' '); Serial.print(sensorSmoothCountLDR); Serial.print(' '); Serial.print(suppressACP); Serial.print(' '); Serial.print(blankHourStart); Serial.println(); Serial.print(blankHourEnd); Serial.print(' '); Serial.print(minDim); Serial.print(' '); Serial.print(antiGhost); Serial.print(' '); Serial.print(dispCount); Serial.print(' '); Serial.print(blankMode); Serial.print(' '); Serial.print(useLDR); Serial.print(' '); Serial.print(slotsMode); Serial.println(); } /* backlightMode = EEPROM.read(EE_BACKLIGHT_MODE); if ((backlightMode < BACKLIGHT_MIN) || (backlightMode > BACKLIGHT_MAX)) { backlightMode = BACKLIGHT_DEFAULT; } redCnl = EEPROM.read(EE_RED_INTENSITY); if ((redCnl < COLOUR_CNL_MIN) || (redCnl > COLOUR_CNL_MAX)) { redCnl = COLOUR_RED_CNL_DEFAULT; } grnCnl = EEPROM.read(EE_GRN_INTENSITY); if ((grnCnl < COLOUR_CNL_MIN) || (grnCnl > COLOUR_CNL_MAX)) { grnCnl = COLOUR_GRN_CNL_DEFAULT; } bluCnl = EEPROM.read(EE_BLU_INTENSITY); if ((bluCnl < COLOUR_CNL_MIN) || (bluCnl > COLOUR_CNL_MAX)) { bluCnl = COLOUR_BLU_CNL_DEFAULT; } hvTargetVoltage = EEPROM.read(EE_HV_VOLTAGE); if ((hvTargetVoltage < HVGEN_TARGET_VOLTAGE_MIN) || (hvTargetVoltage > HVGEN_TARGET_VOLTAGE_MAX)) { hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; } pwmOn = EEPROM.read(EE_PULSE_HI) * 256 + EEPROM.read(EE_PULSE_LO); if ((pwmOn < PWM_PULSE_MIN) || (pwmOn > PWM_PULSE_MAX)) { pwmOn = PWM_PULSE_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } pwmTop = EEPROM.read(EE_PWM_TOP_HI) * 256 + EEPROM.read(EE_PWM_TOP_LO); if ((pwmTop < PWM_TOP_MIN) || (pwmTop > PWM_TOP_MAX)) { pwmTop = PWM_TOP_DEFAULT; // Hmmm, need calibration EEPROM.write(EE_HVG_NEED_CALIB, true); } cycleSpeed = EEPROM.read(EE_CYCLE_SPEED); if ((cycleSpeed < CYCLE_SPEED_MIN) || (cycleSpeed > CYCLE_SPEED_MAX)) { cycleSpeed = CYCLE_SPEED_DEFAULT; } */ if ((dayBlanking < DAY_BLANKING_MIN) || (dayBlanking > DAY_BLANKING_MAX)) { dayBlanking = DAY_BLANKING_DEFAULT; } if ((dimDark < SENSOR_LOW_MIN) || (dimDark > SENSOR_LOW_MAX)) { dimDark = SENSOR_LOW_DEFAULT; } if ((scrollSteps < SCROLL_STEPS_MIN) || (scrollSteps > SCROLL_STEPS_MAX)) { scrollSteps = SCROLL_STEPS_DEFAULT; } if ((dimBright < SENSOR_HIGH_MIN) || (dimBright > SENSOR_HIGH_MAX)) { dimBright = SENSOR_HIGH_DEFAULT; } if ((sensorSmoothCountLDR < SENSOR_SMOOTH_READINGS_MIN) || (sensorSmoothCountLDR > SENSOR_SMOOTH_READINGS_MAX)) { sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; } if ((fadeSteps < FADE_STEPS_MIN) || (fadeSteps > FADE_STEPS_MAX)) { fadeSteps = FADE_STEPS_DEFAULT; } if ((blankHourStart < 0) || (blankHourStart > HOURS_MAX)) { blankHourStart = 0; } if ((blankHourEnd < 0) || (blankHourEnd > HOURS_MAX)) { blankHourEnd = 7; } if ((minDim < MIN_DIM_MIN) || (minDim > MIN_DIM_MAX)) { minDim = MIN_DIM_DEFAULT; } if ((antiGhost < ANTI_GHOST_MIN) || (antiGhost > ANTI_GHOST_MAX)) { antiGhost = ANTI_GHOST_DEFAULT; } if ((blankMode < BLANK_MODE_MIN) || (blankMode > BLANK_MODE_MAX)) { blankMode = BLANK_MODE_DEFAULT; } if ((dateFormat < DATE_FORMAT_MIN) || (dateFormat > DATE_FORMAT_MAX)) { dateFormat = DATE_FORMAT_DEFAULT; } if ((slotsMode < SLOTS_MODE_MIN) || (slotsMode > SLOTS_MODE_MAX)) { slotsMode = SLOTS_MODE_DEFAULT; } } // ************************************************************ // Reset EEPROM values back to what they once were // ************************************************************ void factoryReset() { hourMode = HOUR_MODE_DEFAULT; blankLeading = LEAD_BLANK_DEFAULT; scrollback = SCROLLBACK_DEFAULT; fade = FADE_DEFAULT; fadeSteps = FADE_STEPS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT; dimDark = SENSOR_LOW_DEFAULT; scrollSteps = SCROLL_STEPS_DEFAULT; dimBright = SENSOR_HIGH_DEFAULT; sensorSmoothCountLDR = SENSOR_SMOOTH_READINGS_DEFAULT; dateFormat = DATE_FORMAT_DEFAULT; dayBlanking = DAY_BLANKING_DEFAULT;// backlightMode = BACKLIGHT_DEFAULT;// redCnl = COLOUR_RED_CNL_DEFAULT;// grnCnl = COLOUR_GRN_CNL_DEFAULT;// bluCnl = COLOUR_BLU_CNL_DEFAULT;// hvTargetVoltage = HVGEN_TARGET_VOLTAGE_DEFAULT; suppressACP = SUPPRESS_ACP_DEFAULT; blankHourStart = 0; blankHourEnd = 7; // cycleSpeed = CYCLE_SPEED_DEFAULT; // pwmOn = PWM_PULSE_DEFAULT; // pwmTop = PWM_TOP_DEFAULT; minDim = MIN_DIM_DEFAULT; //antiGhost = ANTI_GHOST_DEFAULT; HV by arduino pwm not use - I prefer MC34063 useLDR = USE_LDR_DEFAULT; blankMode = BLANK_MODE_DEFAULT; slotsMode = SLOTS_MODE_DEFAULT; saveEEPROMValues(); } //********************************************************************************** //********************************************************************************** //* I2C interface * //********************************************************************************** //********************************************************************************** /** * receive information from the master */ void receiveEvent(int bytes) { // the operation tells us what we are getting int operation = Wire.read(); if (operation == I2C_TIME_UPDATE) { // If we're getting time from the WiFi module, mark that we have an active WiFi with a 5 min time out useWiFi = MAX_WIFI_TIME; int newYears = Wire.read(); int newMonths = Wire.read(); int newDays = Wire.read(); int newHours = Wire.read(); int newMins = Wire.read(); int newSecs = Wire.read(); setTime(newHours, newMins, newSecs, newDays, newMonths, newYears); } else if (operation == I2C_SET_OPTION_12_24) { byte readByte1224 = Wire.read(); hourMode = (readByte1224 == 1); EEPROM.write(EE_12_24, hourMode); } else if (operation == I2C_SET_OPTION_BLANK_LEAD) { byte readByteBlank = Wire.read(); blankLeading = (readByteBlank == 1); EEPROM.write(EE_BLANK_LEAD_ZERO, blankLeading); } else if (operation == I2C_SET_OPTION_SCROLLBACK) { byte readByteSB = Wire.read(); scrollback = (readByteSB == 1); EEPROM.write(EE_SCROLLBACK, scrollback); } else if (operation == I2C_SET_OPTION_SUPPRESS_ACP) { byte readByteSA = Wire.read(); suppressACP = (readByteSA == 1); EEPROM.write(EE_SUPPRESS_ACP, suppressACP); } else if (operation == I2C_SET_OPTION_DATE_FORMAT) { dateFormat = Wire.read(); EEPROM.write(EE_DATE_FORMAT, dateFormat); } else if (operation == I2C_SET_OPTION_DAY_BLANKING) { dayBlanking = Wire.read(); EEPROM.write(EE_DAY_BLANKING, dayBlanking); } else if (operation == I2C_SET_OPTION_BLANK_START) { blankHourStart = Wire.read(); EEPROM.write(EE_HOUR_BLANK_START, blankHourStart); } else if (operation == I2C_SET_OPTION_BLANK_END) { blankHourEnd = Wire.read(); EEPROM.write(EE_HOUR_BLANK_END, blankHourEnd); } else if (operation == I2C_SET_OPTION_FADE_STEPS) { fadeSteps = Wire.read(); EEPROM.write(EE_FADE_STEPS, fadeSteps); } else if (operation == I2C_SET_OPTION_SCROLL_STEPS) { scrollSteps = Wire.read(); EEPROM.write(EE_SCROLL_STEPS, scrollSteps); /* } else if (operation == I2C_SET_OPTION_BACKLIGHT_MODE) { backlightMode = Wire.read(); EEPROM.write(EE_BACKLIGHT_MODE, backlightMode); } else if (operation == I2C_SET_OPTION_RED_CHANNEL) { redCnl = Wire.read(); EEPROM.write(EE_RED_INTENSITY, redCnl); } else if (operation == I2C_SET_OPTION_GREEN_CHANNEL) { grnCnl = Wire.read(); EEPROM.write(EE_GRN_INTENSITY, grnCnl); } else if (operation == I2C_SET_OPTION_BLUE_CHANNEL) { bluCnl = Wire.read(); EEPROM.write(EE_BLU_INTENSITY, bluCnl); } else if (operation == I2C_SET_OPTION_CYCLE_SPEED) { cycleSpeed = Wire.read(); EEPROM.write(EE_CYCLE_SPEED, cycleSpeed); */ } else if (operation == I2C_SHOW_IP_ADDR) { ourIP[0] = Wire.read(); ourIP[1] = Wire.read(); ourIP[2] = Wire.read(); ourIP[3] = Wire.read(); } else if (operation == I2C_SET_OPTION_FADE) { fade = Wire.read(); EEPROM.write(EE_FADE, fade); } else if (operation == I2C_SET_OPTION_USE_LDR) { byte readByteUseLDR = Wire.read(); useLDR = (readByteUseLDR == 1); EEPROM.write(EE_USE_LDR, useLDR); } else if (operation == I2C_SET_OPTION_BLANK_MODE) { blankMode = Wire.read(); EEPROM.write(EE_BLANK_MODE, blankMode); } else if (operation == I2C_SET_OPTION_SLOTS_MODE) { slotsMode = Wire.read(); EEPROM.write(EE_SLOTS_MODE, slotsMode); } else if (operation == I2C_SET_OPTION_MIN_DIM) { byte dimHI = Wire.read(); byte dimLO = Wire.read(); minDim = dimHI * 256 + dimLO; EEPROM.write(EE_MIN_DIM_HI, dimHI); EEPROM.write(EE_MIN_DIM_LO, dimLO); } } /** send information to the master */ void requestEvent() { byte configArray[I2C_DATA_SIZE]; int idx = 0; configArray[idx++] = I2C_PROTOCOL_NUMBER; // protocol version configArray[idx++] = encodeBooleanForI2C(hourMode); configArray[idx++] = encodeBooleanForI2C(blankLeading); configArray[idx++] = encodeBooleanForI2C(scrollback); configArray[idx++] = encodeBooleanForI2C(suppressACP); configArray[idx++] = encodeBooleanForI2C(fade); configArray[idx++] = dateFormat; configArray[idx++] = dayBlanking; configArray[idx++] = blankHourStart; configArray[idx++] = blankHourEnd; configArray[idx++] = fadeSteps; configArray[idx++] = scrollSteps;// configArray[idx++] = backlightMode; // configArray[idx++] = redCnl;// configArray[idx++] = grnCnl;// configArray[idx++] = bluCnl; // configArray[idx++] = cycleSpeed; configArray[idx++] = encodeBooleanForI2C(useLDR); configArray[idx++] = blankMode; configArray[idx++] = slotsMode; configArray[idx++] = minDim / 256; configArray[idx++] = minDim % 256; Wire.write(configArray, I2C_DATA_SIZE); } byte encodeBooleanForI2C(boolean valueToProcess) { if (valueToProcess) { byte byteToSend = 1; return byteToSend; } else { byte byteToSend = 0; return byteToSend; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayTime() { NumberArray[5] = second() % 10; NumberArray[4] = second() / 10; NumberArray[3] = minute() % 10; NumberArray[2] = minute() / 10; if (hourMode) { NumberArray[1] = hourFormat12() % 10; NumberArray[0] = hourFormat12() / 10; } else { NumberArray[1] = hour() % 10; NumberArray[0] = hour() / 10; } } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArraySameValue(byte val) { NumberArray[5] = val; NumberArray[4] = val; NumberArray[3] = val; NumberArray[2] = val; NumberArray[1] = val; NumberArray[0] = val; } // ************************************************************ // Break the time into displayable digits // ************************************************************ void loadNumberArrayDate() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: NumberArray[5] = day() % 10; NumberArray[4] = day() / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = (year() - 2000) % 10; NumberArray[0] = (year() - 2000) / 10; break; case DATE_FORMAT_MMDDYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = day() % 10; NumberArray[2] = day() / 10; NumberArray[1] = month() % 10; NumberArray[0] = month() / 10; break; case DATE_FORMAT_DDMMYY: NumberArray[5] = (year() - 2000) % 10; NumberArray[4] = (year() - 2000) / 10; NumberArray[3] = month() % 10; NumberArray[2] = month() / 10; NumberArray[1] = day() % 10; NumberArray[0] = day() / 10; break; } } // ************************************************************ // Break the temperature into displayable digits // ************************************************************ void loadNumberArrayTemp(int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; float temp = getRTCTemp(); int wholeDegrees = int(temp); temp = (temp - float(wholeDegrees)) * 100.0; int fractDegrees = int(temp); NumberArray[3] = fractDegrees % 10; NumberArray[2] = fractDegrees / 10; NumberArray[1] = wholeDegrees % 10; NumberArray[0] = wholeDegrees / 10; } // ************************************************************ // Break the LDR reading into displayable digits // ************************************************************ void loadNumberArrayLDR() { NumberArray[5] = 0; NumberArray[4] = 0; NumberArray[3] = (digitOffCount / 1) % 10; NumberArray[2] = (digitOffCount / 10) % 10; NumberArray[1] = (digitOffCount / 100) % 10; NumberArray[0] = (digitOffCount / 1000) % 10; } // ************************************************************ // Test digits // ************************************************************ void loadNumberArrayTestDigits() { NumberArray[5] = second() % 10; NumberArray[4] = (second() + 1) % 10; NumberArray[3] = (second() + 2) % 10; NumberArray[2] = (second() + 3) % 10; NumberArray[1] = (second() + 4) % 10; NumberArray[0] = (second() + 5) % 10; } // ************************************************************ // Do the Anti Cathode Poisoning // ************************************************************ void loadNumberArrayACP() { NumberArray[5] = (second() + acpOffset) % 10; NumberArray[4] = (second() / 10 + acpOffset) % 10; NumberArray[3] = (minute() + acpOffset) % 10; NumberArray[2] = (minute() / 10 + acpOffset) % 10; NumberArray[1] = (hour() + acpOffset) % 10; NumberArray[0] = (hour() / 10 + acpOffset) % 10; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayConfInt(int confValue, int confNum) { NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = (confValue / 1) % 10; NumberArray[2] = (confValue / 10) % 10; NumberArray[1] = (confValue / 100) % 10; NumberArray[0] = (confValue / 1000) % 10; } // ************************************************************ // Show a boolean configuration value // ************************************************************ void loadNumberArrayConfBool(boolean confValue, int confNum) { int boolInt; if (confValue) { boolInt = 1; } else { boolInt = 0; } NumberArray[5] = (confNum) % 10; NumberArray[4] = (confNum / 10) % 10; NumberArray[3] = boolInt; NumberArray[2] = 0; NumberArray[1] = 0; NumberArray[0] = 0; } // ************************************************************ // Show an integer configuration value // ************************************************************ void loadNumberArrayIP(byte byte1, byte byte2) { NumberArray[5] = (byte2) % 10; NumberArray[4] = (byte2 / 10) % 10; NumberArray[3] = (byte2 / 100) % 10; NumberArray[2] = (byte1) % 10; NumberArray[1] = (byte1 / 10) % 10; NumberArray[0] = (byte1 / 100) % 10; } // ************************************************************ // Do a single complete display, including any fading and // dimming requested. Performs the display loop // DIGIT_DISPLAY_COUNT times for each digit, with no delays. (1000) // This is the heart of the display processing! // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // use OnOff[i] - current state of digit - not able to read 74hc595 registers // ************************************************************ void outputDisplay() { float digitSwitchTimeFloat; int tmpDispType; // digitOff(5); //all correctly but .. 36 cycles per second // digitOff(4); // digitOff(3); // digitOff(2); // digitOff(1); // digitOff(0); // shifter.setAll(HIGH); //turn off all 6 K155ID1 // shifter.write(); // set registers 74HC595 /* byte l0 = NumberArray[0] ; //fast Shifter byte for lamp 0 - tens hours byte l1 = NumberArray[1] ; byte l2 = NumberArray[2] ; byte l3 = NumberArray[3] ; byte l4 = NumberArray[4] ; byte l5 = NumberArray[5] ; //ones of seconds */ // used to blank all leading digits if 0 boolean leadingZeros = true; for ( int i = 0 ; i < DIGIT_COUNT ; i ++ ) { // tubes 0 - 5, 5-ones seconds, 0 -tens hours // OnOff[i]= 0; if (blankTubes) { tmpDispType = BLANKED; } else { tmpDispType = displayType[i]; } switch (tmpDispType) { case BLANKED: { digitOnTime[i] = DIGIT_DISPLAY_NEVER; digitOffTime[i] = DIGIT_DISPLAY_ON; //0 break; } case DIMMED: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 digitOffTime[i] = DIM_VALUE; break; } case BRIGHT: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 0 .... 1000 on -0 *20mks off 20000 mks ~~ always on digitOffTime[i]= DIGIT_DISPLAY_OFF; //1000 //digitOffTime = 995; break; } case FADE: case NORMAL: { digitOnTime[i] = DIGIT_DISPLAY_ON; //0 digitOffTime[i] = digitOffCount; break; } case BLINK: { if (blinkState) { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; } else { digitOnTime[i] = DIGIT_DISPLAY_NEVER; // -1 = off all cycle digitOffTime[i] = DIGIT_DISPLAY_ON; } break; } case SCROLL: { digitOnTime[i] = DIGIT_DISPLAY_ON; digitOffTime[i] = digitOffCount; break; } } // Do scrollback when we are going to 0 if ((NumberArray[i] != currNumberArray[i]) && (NumberArray[i] == 0) && scrollback) { tmpDispType = SCROLL; } // manage scrolling, count the digits down if (tmpDispType == SCROLL) { digitSwitchTime[i] = DIGIT_DISPLAY_OFF; //1000 if (NumberArray[i] != currNumberArray[i]) { if (fadeState[i] == 0) { // Start the fade fadeState[i] = scrollSteps; } if (fadeState[i] == 1) { // finish the fade .. ??scroll fadeState[i] = 0; if (i>0) currNumberArray[i] = currNumberArray[i-1]; //wrong - for fade not scroll - fade digit = digit - 1 //currNumberArray[i] = currNumberArray[i] -1 ; } else if (fadeState[i] > 1) { // Continue the scroll countdown fadeState[i] = fadeState[i] - 1; } } // manage fading, each impression we show 1 fade step less of the old // digit and 1 fade step more of the new } else if (tmpDispType == FADE) { if (NumberArray[i] != currNumberArray[i]) { // first time currNumberArray[i] = 10 - k155id1 turn off output when input code 10-15, nixie subroutine do the same if (fadeState[i] == 0) { // if (i != 5) { // no fade for seconds lamp #5 (#0 - tens hours) // Start the fade - this for old digit - darken, then off fadeState[i] = fadeSteps; // set value for Fade - 46 impr/sec -> 45 max, 49 --> 47 digitSwitchTime[i] = (int) fadeState[i] * fadeStep ; // calc value - 2 when dark 20 when brightly 45*2 = 120 max bright when dark // turn on digit slowly // digitOnTime[i] = ((int) fadeState[i] * fadeStep) -20 ; // calc value - 2 when dark 20 when brightly 45*2 = 120 max bright when dark 1 * 20 =20 'on timer' - bright, 45*20 =900 slow on // } } } if (fadeState[i] == 1) { // finish the fade fadeState[i] = 0; currNumberArray[i] = NumberArray[i]; digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; //1000 // digitOnTime[i] = 0 ; // 1 * 20 =20 'on timer' - bright, 45*20 =900 slow on } else if (fadeState[i] > 1) { // Continue the fade fadeState[i] = fadeState[i] - 1; digitSwitchTime[i] = (int) fadeState[i] * fadeStep; // digitOnTime[i]=digitOnTime[i] - fadeStep; // if (digitOnTime[i] <0) digitOnTime[i]=0; } } else { // finish the fade digitSwitchTime[i] = DIGIT_DISPLAY_COUNT; currNumberArray[i] = NumberArray[i]; // fadeState[i] =0 bulb is Fade but Fade not start, copy current digit to currNumberArray[i], wait for change time digitOnTime[i] = 0 ; } //} /* //for turn on lapm slowly (minutes - tens of seconds) if (tmpDispType == FADE) { } */ // 6 tubes at one time first loop } // 6 tubes set - inner cycle 1000 times (dispCount) (change -2-nd loop all together 6 digits) for (int timer = 0 ; timer < dispCount ; timer++) { if (timer == digitOnTime[0]) { //fade or transition - turn on together 2 digit // digitOn(i, currNumberArray[i],l0,l1,l2,l3,l4,l5); // i=0 .. i=5 lamp ten of hour ... ones of seconds, currNumberArray[i] - digit to display at [i] position digitOn(0, NumberArray[0]); } if (timer == digitOnTime[1]) { digitOn(1, NumberArray[1]); } if (timer == digitOnTime[2]) { digitOn(2, NumberArray[2]); } if (timer == digitOnTime[3]) { digitOn(3, NumberArray[3]); } if (timer == digitOnTime[4]) { digitOn(4, NumberArray[4]); } if (timer == digitOnTime[5]) { digitOn(5, NumberArray[5]); } if (timer == digitSwitchTime[0]) { //fade or transition - turn on together 2 digit // SetSN74141Chip(i,NumberArray[i],l0,l1,l2,l3,l4,l5); SetSN74141Chip(0,currNumberArray[0]); } if (timer == digitSwitchTime[1]) { SetSN74141Chip(1,currNumberArray[1]); } if (timer == digitSwitchTime[2]) { SetSN74141Chip(2,currNumberArray[2]); } if (timer == digitSwitchTime[3]) { SetSN74141Chip(3,currNumberArray[3]); } if (timer == digitSwitchTime[4]) { SetSN74141Chip(4,currNumberArray[4]); } if (timer == digitSwitchTime[5]) { SetSN74141Chip(5,currNumberArray[5]); } if (timer == digitOffTime[0]) { digitOff(0); } if (timer == digitOffTime[1]) { digitOff(1); } if (timer == digitOffTime[2]) { digitOff(2); } if (timer == digitOffTime[3]) { digitOff(3); } if (timer == digitOffTime[4]) { digitOff(4); } if (timer == digitOffTime[5]) { digitOff(5); } } // Deal with blink, calculate if we are on or off blinkCounter++; if (blinkCounter == BLINK_COUNT_MAX) { blinkCounter = 0; blinkState = !blinkState; } } // ************************************************************ // Set a digit with the given value and turn the HVGen on // Assumes that all digits have previously been turned off // by a call to "digitOff" // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib // optimize for speed ! up to 300000 cycles/1s // //next try optimize - 6 digit at one time // ************************************************************ // void digitOn(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void digitOn(int digit, int value) { OnOff[digit]= 1; // now digit turns on .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) nixie (digit*4,value); /* switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { // tens of hours tube // nixie (20, value); //seconds - lamp 5 -6 - Shifter fast setPin 4 pins connected to decoder K155ID1 74141 // nixie (8, value); //minutes // nixie subroutine switch by value nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { //tube show ones of seconds nixie (20, value); //seconds - lamp 5 -6 } } */ // turn off (dynamic) 1/50000 s * digitOffTime if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now 1/50/1000*6 sec // выключаются цифры которые снижают яркость или сдвигаются или в эффекте затемнения shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } shifter.write(); // set registers 74HC595 //SetSN74141Chip(value); // do here - shifter_write(); // TCNT1 = 0; // Thanks Phil! // TCCR1A = tccrOn; } // ************************************************************ // Finish displaying a digit and turn the HVGen on // // Santosha - turn off all digits use Shifter - code 0xff - off 74141 // ************************************************************ void digitOff(int i) { // TCCR1A = tccrOff; //digitalWrite(anodePins[digit], LOW); OnOff[i] = 0; // turn all digits off - equivalent to digitalWrite(ledPin_a_n,LOW); (n=1,2,3,4,5,6) but much faster //shifter.setAll(HIGH); int j=i*4; shifter.setPin(j, HIGH); shifter.setPin(j+1, HIGH); shifter.setPin(j+2, HIGH); shifter.setPin(j+3, HIGH); /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ // nixie (j,10); //10=off shifter.write(); // set registers 74HC595 /* PORTC = PORTC & B11110011; PORTD = PORTD & B11101000; */ } // ************************************************************ // Decode the value to send to the 74141 and send it // We do this via the decoder to allow easy adaptation to // other pin layouts. // // Santosha - edit for 6 K155ID1 - 3 - 74hc595, Shifter lib - set one digit "value", set another as is // decodeDigit not use - digit conection direct, 0-0 , 1-1 into nixie subroutine // not able reading current state of registers - calculate which digits need turn on at this time - !test now (OK) // 46 impression per sec - 53 (correction) turn off 1 digit, OnOff variable not use - switch digits for Fade // this use for Fade - one digit change to another // Fade - 60 steps - each step * 120 minDim // 30-300 times see OK ?? (max bright 1000) not more 1 second - when 46 impr/ sec check - not more 45 // ************************************************************ // void SetSN74141Chip(int digit, int value, byte l0,byte l1,byte l2,byte l3,byte l4,byte l5) void SetSN74141Chip(int digit, int value) { // note that digit turns on but not save state into OnOff variable OnOff[digit]= 1; // now digit turns off (on for transition) .. по отладке 46 раз в секунду основной цикл - не моргает. (46000 /sec digit) // test - turn on only current digit (faster) do not change state of another registry bits nixie (digit*4,value); /* switch (digit) { // case 0: PORTC = PORTC | B00001000; break; // PC3 - equivalent to digitalWrite(ledPin_a_1,HIGH); case 0: { nixie (0, value); //hours lamp 1-2 } // case 1: PORTC = PORTC | B00000100; break; // PC2 - equivalent to digitalWrite(ledPin_a_2,HIGH); case 1: { nixie (4, value); } // case 2: PORTD = PORTD | B00010000; break; // PD4 - equivalent to digitalWrite(ledPin_a_3,HIGH); case 2: { nixie (8, value); //minutes } // case 3: PORTD = PORTD | B00000100; break; // PD2 - equivalent to digitalWrite(ledPin_a_4,HIGH); case 3: { nixie (12, value); } // case 4: PORTD = PORTD | B00000010; break; // PD1 - equivalent to digitalWrite(ledPin_a_5,HIGH); case 4: { nixie (16, value); } // case 5: PORTD = PORTD | B00000001; break; // PD0 - equivalent to digitalWrite(ledPin_a_6,HIGH); case 5: { nixie (20, value); //seconds - lamp 5 -6 } } */ // //useless .. set 2 - digit at one time is ok /* if (OnOff[0] == 0 ) { // state for this time - off digits if they turn off now shifter.setPin(0, HIGH); shifter.setPin(1, HIGH); shifter.setPin(2, HIGH); shifter.setPin(3, HIGH); } if (OnOff[1] == 0 ) { shifter.setPin(4, HIGH); shifter.setPin(5, HIGH); shifter.setPin(6, HIGH); shifter.setPin(7, HIGH); } if (OnOff[2] == 0 ) { shifter.setPin(8, HIGH); shifter.setPin(9, HIGH); shifter.setPin(10, HIGH); shifter.setPin(11, HIGH); } if (OnOff[3] == 0 ) { shifter.setPin(12, HIGH); shifter.setPin(13, HIGH); shifter.setPin(14, HIGH); shifter.setPin(15, HIGH); } if (OnOff[4] == 0 ) { shifter.setPin(16, HIGH); shifter.setPin(17, HIGH); shifter.setPin(18, HIGH); shifter.setPin(19, HIGH); } if (OnOff[5] == 0 ) { shifter.setPin(20, HIGH); shifter.setPin(21, HIGH); shifter.setPin(22, HIGH); shifter.setPin(23, HIGH); } */ shifter.write(); // set registers 74HC595 - turn on output /* // Map the logical numbers to the hardware pins we send to the SN74141 IC int decodedDigit = decodeDigit[num1]; // Mask all digit bits to 0 byte portb = PORTB; portb = portb & B11001010; // Set the bits we need switch ( decodedDigit ) { case 0: break; // a=0;b=0;c=0;d=0 case 1: portb = portb | B00100000; break; // a=1;b=0;c=0;d=0 case 2: portb = portb | B00000100; break; // a=0;b=1;c=0;d=0 case 3: portb = portb | B00100100; break; // a=1;b=1;c=0;d=0 case 4: portb = portb | B00000001; break; // a=0;b=0;c=1;d=0 case 5: portb = portb | B00100001; break; // a=1;b=0;c=1;d=0 case 6: portb = portb | B00000101; break; // a=0;b=1;c=1;d=0 case 7: portb = portb | B00100101; break; // a=1;b=1;c=1;d=0 case 8: portb = portb | B00010000; break; // a=0;b=0;c=0;d=1 case 9: portb = portb | B00110000; break; // a=1;b=0;c=0;d=1 default: portb = portb | B00110101; break; // a=1;b=1;c=1;d=1 } PORTB = portb; */ } // atmega8 basic //Shiftout Portb.4 , Portb.0 , Seco , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Mine , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Hour , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Dat , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Month , 3 , 8 , 3 //Shiftout Portb.4 , Portb.0 , Year , 3 , 8 , 3 void nixie (int n, int val) { // use 74141 switch (val) { case 0: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 1: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 2: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 3: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, LOW); break; case 4: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 5: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 6: shifter.setPin(n, LOW); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 7: shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, LOW); break; case 8: shifter.setPin(n, LOW); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 9: shifter.setPin(n, HIGH); shifter.setPin(n + 1, LOW); shifter.setPin(n + 2, LOW); shifter.setPin(n + 3, HIGH); break; case 10: //off shifter.setPin(n, HIGH); shifter.setPin(n + 1, HIGH); shifter.setPin(n + 2, HIGH); shifter.setPin(n + 3, HIGH); break; } } // ************************************************************ // Display preset - apply leading zero blanking // ************************************************************ void applyBlanking() { // If we are not blanking, just get out if (blankLeading == false) { return; } // We only want to blank the hours tens digit if (NumberArray[0] == 0) { if (displayType[0] != BLANKED) { displayType[0] = BLANKED; } } } // ************************************************************ // Display preset // ************************************************************ void allFadeOrNormal(boolean blanking) { if (fade) { allFade(); } else { allNormal(); } if (blanking) { applyBlanking(); } } // ************************************************************ // Display preset // ************************************************************ void allFade() { if (displayType[0] != FADE) displayType[0] = FADE; if (displayType[1] != FADE) displayType[1] = FADE; if (displayType[2] != FADE) displayType[2] = FADE; if (displayType[3] != FADE) displayType[3] = FADE; if (displayType[4] != FADE) displayType[4] = FADE; if (displayType[5] != FADE) displayType[5] = FADE; } // ************************************************************ // Display preset // ************************************************************ void allBright() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightYearsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight0and1(); break; case DATE_FORMAT_MMDDYY: highlight4and5(); break; case DATE_FORMAT_DDMMYY: highlight4and5(); break; } } // ************************************************************ // highlight years taking into account the date format // ************************************************************ void highlightMonthsDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight2and3(); break; case DATE_FORMAT_MMDDYY: highlight0and1(); break; case DATE_FORMAT_DDMMYY: highlight2and3(); break; } } // ************************************************************ // highlight days taking into account the date format // ************************************************************ void highlightDaysDateFormat() { switch (dateFormat) { case DATE_FORMAT_YYMMDD: highlight4and5(); break; case DATE_FORMAT_MMDDYY: highlight2and3(); break; case DATE_FORMAT_DDMMYY: highlight0and1(); break; } } // ************************************************************ // Display preset, highlight digits 0 and 1 // ************************************************************ void highlight0and1() { DIM_VALUE = 3; if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 2 and 3 // ************************************************************ void highlight2and3() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != DIMMED) displayType[4] = DIMMED; if (displayType[5] != DIMMED) displayType[5] = DIMMED; } // ************************************************************ // Display preset, highlight digits 4 and 5 // ************************************************************ void highlight4and5() { DIM_VALUE = 3; if (displayType[0] != DIMMED) displayType[0] = DIMMED; if (displayType[1] != DIMMED) displayType[1] = DIMMED; if (displayType[2] != DIMMED) displayType[2] = DIMMED; if (displayType[3] != DIMMED) displayType[3] = DIMMED; if (displayType[4] != BRIGHT) displayType[4] = BRIGHT; if (displayType[5] != BRIGHT) displayType[5] = BRIGHT; } // ************************************************************ // Display preset // ************************************************************ void allNormal() { DIM_VALUE = MIN_DIM_DEFAULT; if (displayType[0] != NORMAL) displayType[0] = NORMAL; if (displayType[1] != NORMAL) displayType[1] = NORMAL; if (displayType[2] != NORMAL) displayType[2] = NORMAL; if (displayType[3] != NORMAL) displayType[3] = NORMAL; if (displayType[4] != NORMAL) displayType[4] = NORMAL; if (displayType[5] != NORMAL) displayType[5] = NORMAL; } // ************************************************************ // Display preset // ************************************************************ void displayConfig() { if (displayType[0] != BRIGHT) displayType[0] = BRIGHT; if (displayType[1] != BRIGHT) displayType[1] = BRIGHT; if (displayType[2] != BRIGHT) displayType[2] = BRIGHT; if (displayType[3] != BRIGHT) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig3() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != NORMAL) displayType[1] = BRIGHT; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void displayConfig2() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != NORMAL) displayType[2] = BRIGHT; if (displayType[3] != NORMAL) displayType[3] = BRIGHT; if (displayType[4] != BLINK) displayType[4] = BLINK; if (displayType[5] != BLINK) displayType[5] = BLINK; } // ************************************************************ // Display preset // ************************************************************ void allBlanked() { if (displayType[0] != BLANKED) displayType[0] = BLANKED; if (displayType[1] != BLANKED) displayType[1] = BLANKED; if (displayType[2] != BLANKED) displayType[2] = BLANKED; if (displayType[3] != BLANKED) displayType[3] = BLANKED; if (displayType[4] != BLANKED) displayType[4] = BLANKED; if (displayType[5] != BLANKED) displayType[5] = BLANKED; } // ************************************************************ // Reset the seconds to 00 // ************************************************************ void resetSecond() { byte tmpSecs = 0; setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 Sec // ************************************************************ void incSecond() { byte tmpSecs = second(); tmpSecs++; if (tmpSecs >= SECS_MAX) { tmpSecs = 0; } setTime(hour(), minute(), tmpSecs, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 min // ************************************************************ void incMins() { byte tmpMins = minute(); tmpMins++; if (tmpMins >= MINS_MAX) { tmpMins = 0; } setTime(hour(), tmpMins, 0, day(), month(), year()); setRTC(); } // ************************************************************ // increment the time by 1 hour // ************************************************************ void incHours() { byte tmpHours = hour(); tmpHours++; if (tmpHours >= HOURS_MAX) { tmpHours = 0; } setTime(tmpHours, minute(), second(), day(), month(), year()); setRTC(); } // ************************************************************ // increment the date by 1 day // ************************************************************ void incDays() { byte tmpDays = day(); tmpDays++; int maxDays; switch (month()) { case 4: case 6: case 9: case 11: { maxDays = 31; break; } case 2: { // we won't worry about leap years!!! maxDays = 28; break; } default: { maxDays = 31; } } if (tmpDays > maxDays) { tmpDays = 1; } setTime(hour(), minute(), second(), tmpDays, month(), year()); setRTC(); } // ************************************************************ // increment the month by 1 month // ************************************************************ void incMonths() { byte tmpMonths = month(); tmpMonths++; if (tmpMonths > 12) { tmpMonths = 1; } setTime(hour(), minute(), second(), day(), tmpMonths, year()); setRTC(); } // ************************************************************ // increment the year by 1 year // ************************************************************ void incYears() { byte tmpYears = year() % 100; tmpYears++; if (tmpYears > 50) { tmpYears = 15; } setTime(hour(), minute(), second(), day(), month(), 2000 + tmpYears); setRTC(); } // ************************************************************ // Check the blanking // ************************************************************ boolean checkBlanking() { // Check day blanking, but only when we are in // normal time mode if (currentMode == MODE_TIME) { switch (dayBlanking) { case DAY_BLANKING_NEVER: return false; case DAY_BLANKING_HOURS: return getHoursBlanked(); case DAY_BLANKING_WEEKEND: return ((weekday() == 1) || (weekday() == 7)); case DAY_BLANKING_WEEKEND_OR_HOURS: return ((weekday() == 1) || (weekday() == 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKEND_AND_HOURS: return ((weekday() == 1) || (weekday() == 7)) && getHoursBlanked(); case DAY_BLANKING_WEEKDAY: return ((weekday() > 1) && (weekday() < 7)); case DAY_BLANKING_WEEKDAY_OR_HOURS: return ((weekday() > 1) && (weekday() < 7)) || getHoursBlanked(); case DAY_BLANKING_WEEKDAY_AND_HOURS: return ((weekday() > 1) && (weekday() < 7)) && getHoursBlanked(); case DAY_BLANKING_ALWAYS: return true; } } } // ************************************************************ // If we are currently blanked based on hours // ************************************************************ boolean getHoursBlanked() { if (blankHourStart > blankHourEnd) { // blanking before midnight return ((hour() >= blankHourStart) || (hour() < blankHourEnd)); } else if (blankHourStart < blankHourEnd) { // dim at or after midnight return ((hour() >= blankHourStart) && (hour() < blankHourEnd)); } else { // no dimming if Start = End return false; } } // ************************************************************ // Set the tubes and LEDs blanking variables based on blanking mode and // blank mode settings // ************************************************************ void setTubesAndLEDSBlankMode() { if (blanked) { switch(blankMode) { case BLANK_MODE_TUBES: { blankTubes = true; blankLEDs = false; break; } case BLANK_MODE_LEDS: { blankTubes = false; blankLEDs = true; break; } case BLANK_MODE_BOTH: { blankTubes = true; blankLEDs = true; break; } } } else { blankTubes = false; blankLEDs = false; } } /* // ************************************************************ // Show a random RGB colour: used to indicate a factory reset // ************************************************************ void randomRGBFlash(int delayVal) { digitalWrite(tickLed, HIGH); if (random(3) == 0) { digitalWrite(RLed, HIGH); } if (random(3) == 0) { digitalWrite(GLed, HIGH); } if (random(3) == 0) { digitalWrite(BLed, HIGH); } delay(delayVal); digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); delay(delayVal); } */ /* // ************************************************************ // Used to set the LEDs during test mode // ************************************************************ void setLedsTestPattern(unsigned long currentMillis) { unsigned long currentSec = currentMillis / 1000; byte phase = currentSec % 4; digitalWrite(tickLed, LOW); digitalWrite(RLed, LOW); digitalWrite(GLed, LOW); digitalWrite(BLed, LOW); if (phase == 0) { digitalWrite(tickLed, HIGH); } if (phase == 1) { digitalWrite(RLed, HIGH); } if (phase == 2) { digitalWrite(GLed, HIGH); } if (phase == 3) { digitalWrite(BLed, HIGH); } } */ // ************************************************************ // Jump to a new position in the menu - used to skip unused items // ************************************************************ void setNewNextMode(int newNextMode) { nextMode = newNextMode; currentMode = newNextMode - 1; }
http://youtu.be/vxJvNRIcBCk
https://top-radio.ru/web/mayak там есть настройка часов – будет схемка по отлавливанию сигналов но лучше с приемника – она есть в интернете.
https://raw.githubusercontent.com/santosha2003/ArdunixNix6/master/ardunixFade9_6_digit/ardunixFade9_6_digit.ino
** еще раз – от оригинала отличается 6 дешифраторами и еще источник до 25 ватт от 12 вольт – как у поджига ксеноновой фары, все эффекты есть и работают, надо запаять фоторезистор и 1 кнопку управления. Если раньше такого не приходилось делать – поиск – как начать работу с ардуино или как запрограммировать.
- еще не одна будет правка – например я хочу минутную цифру переключать 3 секунды и завел в секундный цикл еще подсчет 3 секунд- и чтобы не сразу загоралась как секунда а плавнее, а старая цифра гасла бы тоже секунды 2-3. Придется в таймере (timer) обратный отсчет замутить.
Фото РГО Российского географического общества (не спелео) Рысь котенок рысенок. Крупная кошка есть в Подмосковье на юго востоке юге и больше на северо – западе и в Тверской области. Их мало. В районе Лотошино у границы леса на дачах надо осторожно открывать чердаки – сначала пошевелить большой палкой. В Чеховском да и в районе Малино Непецино Егорьевск видели. К этой кошке надо относится с уважением – не прогонять, она сама уйдет, но людей не боится, хотя не нападает обычно, у нее есть своя еда в природе. Зайцы, косули и даже покрупнее добыча, и она очень важна в дикой природе – регулирует численность животных.
Кто сейчас отдыхает или работает в районе Клязьминского водохранилища это где Бухта Радости Жостово может Мытищи или Вешки там сейчас прогуливается мишка он зачем то сбежал из вольера. Крупный лесной зверь хочет чтобы его отвезли обратно если видели то есть мчс или ветеринары, пока не убежал далеко или не натворил чего.
другие конструкции – http://robocua.blogspot.com/2014/12/slvik-clock-vi.html https://github.com/clockspot/arduino-clock https://habr.com/ru/post/534278/
образец для этих часов – https://radiokot.ru/konkursCatDay2017/03/ github santosha2003 если есть изменения, только другой источник питания, добавлен декатрон и все таки 6 дешифраторов по одному на лампу. Зато без анодных ключей. Подобран режим – динамический но можно и статику! Эффекты работают только в динамике. При резисторах 18 килоом и вместе с декатроном 300 миллиампер от 12 вольт, батарея 18 ампер часов требует зарядки ну раза 2 в неделю, это на полной яркости и с лампами ИН1 они не слабенькие. Скорректирована программа – пока без подсветки и установки по wi-fi – в программе есть оригинальной. Оставил режим 49 или 46 с эффектами выполнений цикла программы в секунду. никаких разгонов все на 16 мегагерц, ардуина ch340g китайской сборки, в секунде 1000 миллисекунд. Описани настроек- по русски – есть еще перевод на РадиоКоте. В настройку времени переходят при нажатии кнопки – сделал клавишу – 2 секунды и отпустить , перебор режимов на 5 секунд – часы – число и год – температура – ( на видео ну да сейчас в Москве 32 градуса! ) – настройка фоторезистора – 90 тысячных это темно а 999 это светло – полная яркость – число _оборотов_ цикла 49 или 46 – за цикл лампы успевают 1000 раз переключиться и это дает эффекты плавного переключения и регулиовку яркости. 8 секунд нажать кнопку держать и отпустить – проверка и прожиг катодов (не больше минуты!)
наверно правильная настройка 0 07 . 1 08 . 1 09 . 0 10 . 0 11 . 1 15 . 1 16 . 2 17. 60 18 . 4 20 . (4 21) 1 22.
7 24 часа
8 гасить нули
9 сдвиг 1 красиво
10 плавная смена цифр 1 ( но 46 смен в секунду а не 49)
11 американский формат времени
12 днем выключать (0-не выкл)
15 не перебирать цифры ночью (1)
16 использовать фоторезистор 1
17 не гасить ничего (2)
18 19 число шагов смены цифр (60)
20 21 шаги сдвига (4-9)
22 как однорукий бандит – прокрутка секунд и минут (1)
The Arduino Nixie Clock
Часы Arduino Nixie – это прекрасное сочетание старого и нового, и как следствие высокая точность, низкая потребляемая мощность, оригинальный дизайн и схемотехника. Часы станут украшением вашого дома.
Часы имеют следующие функции:
• Последние технологии, высоконадежные и точные.
• Разные варианты исполнения и дизайна во многих сотнях проданных часов.
• На основе микроконтроллера Arduino: легко программировать хорошо документированный.
• Открытый исходный код! Ничто не скрыто в этих часах. (Вы можете изменять и загружать программное обеспечение).
• Низкое энергопотребление. Еще ниже если применен источник питания на mc34063 с управлением полевиком через 2 транзистора и от 12 вольт.
• Длительный срок службы ламп: Антиотравление катодов (ACP) и настраиваемое гашение гарантирует, что лампы будут оставаться работоспособными в течение многих лет.
• Настраиваемое гашение индикации и автоматическая регулировка яркости, используемые в этой конструкции, продлевают срок службы ламп.
• Все настройки сохраняются в энергонезависимой памяти.
• Подсветка RGB позволяет установить практически любой цвет, а также разные режимы подсветки.
• Наличие фоторезистора позволяет автоматически регулировать яркость подсветки и дисплея, что также способствует увеличению срока службы ламп. Это также повышает комфортность пользования в ночное время.
• Абсолютно бесшумная работа. Некоторые часы Nixie издают раздражающее «гудение» или «шипение», которое особенно раздражает, если вы установили часы в спальне.
• Настраиваемое автоматическое отключение индикации в конце рабочего дня или в выходные дни продлевает срок службы ламп.
• Настраиваемый режим гашения дисплея для увеличения срока службы ламп.
• Настраиваемый режим антиотравления катодов в ночное время чтобы не беспокоить при минимальной яркости индикации.
• Высоковольтный генератор автоматически откалибрует себя в соответствии с вашими лампами и источником питания, как следствие типичное потребление около 2 Вт в режиме максимальной яркости, 0,4 Вт при минимальной яркости.
• Высокая точность при использовании модуля RTC DS3231: Точность ± 2 ppm от 0 ° C до + 40 ° C. (Максимум 1 минута в год).
• Срок службы батареи модуля RTC должен составлять около 3 лет при нормальном использовании.
• Сохраняет дату и время даже при выключении.
• Компенсация высокосного года.
• Чрезвычайно точные при использовании дополнительного модуля Wifi: Время, которое никогда не убегает, всегда правильно с точностью до 1 секунды.
• Автоматический переход на летнее время, учет високосных годов.
Конструкцию может повторить ученик старших классов или студент(ка) смотри видео по часам и катушке Теслы – которые на карантине – только надо знать про осторожность с высоким напряжением.
Меры предосторожности
Напряжение в цепи высоковольтного преобразователя может достичь в пике 400 В! а по этой схеме и 1000.
Будьте осторожны! Удар от высоковольтной цепи часов – это, по крайней мере, неприятный укус. В худшем случае это может убить вас. Мы отказываемся от какой-либо ответственности в случае травмы или смерти. Вы должны иметь соответствующую квалификацию для сборки часов.
ПРИМЕЧАНИЯ: Если вы не знаете, что это значит, не используйте часы! Прикосновение к конденсатору 630 вольт даже в сухом помещении это нежелательно.
Общая информация
Часы имеют разные режимы работы, которые вы выбираете с помощью кнопки.
Первый запуск и калибровка.
Когда вы включите часы в первый раз после сборки они перейдут в «режим запуска». Этот режим предназначен для упрощения настройки аппаратного обеспечения. В этом режиме идет циклический перебор цифр «0» – «9». (От себя добавлю что этот режим здорово помог мне при первом запуске, т.к. у меня сразу перебор шел так: 5, 4, 3, 2, 1, 0, 9, 8, 7, 6 и т.д. Достоинство этих часов в том что при разводке платы катоды ламп к К155ИД1 можно подключать как угодно, изменив при этом скетч под себя).
Чтобы выйти из этого режима нажмите кнопку и удерживайте её. Часы перейдут в режим калибровки высоковольтного генератора и на дисплее появится «88:88:88», кнопку отпустите.
Часы будут отображать «88:88:88» в течение нескольких секунд: происходит калибровка высоковольтного генератора в соответствии с примененным адаптером питания. Во время калибровки вы можете услышать какие-то слабые потрескивающие шумы от генератора. Это нормально. После завершения калибровки на дисплее будет отображен в течении примерно 2-х секунд номер версии прошивки («00:48:05»). Затем часы перейдут в нормальный режим работы.
Процесс запуска смотрите здесь:
Как только вы выйдете из режима запуска, то при последующих включениях он не будет вновь запускаться пока вы не выполните сброс настроек (см. ниже).
Режим часов
После первого запуска каждый раз, когда вы включаете часы они переходят в обычный режим часов и отображают время. Каждые 10 минут (в «xx: x9: 15» часы переходят в режим антиотравления катодов в котором идет перебор всех цифр при повышенной яркости в течение примерно 15 секунд. Это не ошибка! Важно поддерживать лампы в работоспособном состоянии.
Источники тактирования
Часы могут использовать либо модуль RTC, со встроенной батареей, либо модуль WiFi. Если вы установите оба варианта, будет использоваться RTC, а модуль Wi-Fi будет проигнорирован!
Получение времени через WiFi модуль
Более актуальным является получение времени через нашу домашнюю сеть WiFi для периодического получения из источников времени в Интернете. Это позволяет поддерживать точность до 1 секунды, и автоматически переходить на летнее время. Вы настраиваете модуль один раз и конфигурация сохраняется навсегда.
Кроме того, модуль времени WiFi дает вам простой в настройке интерфейс, который вы можете использовать для настройки часов с помощью планшета, телефона или компьютера.
Для информации
Обычно часы находятся в режиме отображения времени. Если вы нажмете кнопку то для разной продолжительности нажатия будут происходить разные события:
«Короткое нажатие» (менее 1 секунды): переход в режимы отображения даты , температуры и т.д. (см. ниже).
«Среднее нажатие» (более 1 секунды): часы перейдут в «Режим настройки». Если у вас есть модуль WiFi, вы можете изменить настройки с помощью браузера.
«Длительное нажатие» (более 8 секунд): часы перейдут в «Режим восстановления ламп». Прочтите раздел «Режим восстановления ламп» перед его использованием. Этот режим может повредить лампы если вы используете его неправильно!
Режим отображения времени
Обычно часы показывают время. Чтобы показать дополнительную информацию, нажмите кнопку как «Короткое» нажатие. Каждое нажатие вызывает переход к отображению следующего параметра (см. ниже). Если кнопку не нажимать то через 5 секунд дисплей вернется к нормальному отображению времени.
Режим Описание Значение
Дата Будет показана текущая дата.
Температура Температура внутри корпуса. Значение в градусах Цельсия. Если значение выше 40, необходимо улучшить вентиляцию в корпусе, потому что температурная компенсация в DS3231не может работать при таких высоких значениях и срок службы часов может уменьшиться, а время может дрейфовать.
Примечание: этот режим пропускается, если модуль RTC не подключен.
LDR Уровень освещенности. Показывает текущую освещенность фоторезистора. Это нормализованное значение и колеблется от 100 (затемнённый) до 999 (ярко освещен). Параметр используется для авторегулировки яркости ламп и подсветки. 100: темно
999: ярко
Версия Номер версии прошивки. 00:48:05
IP адрес
Часть 1 Если у вас подключен модуль WiFi, будут показаны первые две цифры 4-значного IP-адреса. Обычно этот адрес начинается с «192.168».
Примечание. IP-адрес пропускается, если модуль Wi-Fi не подключен. Пример:
«192,168»
IP адрес
часть 2 Если у вас подключен модуль WiFi, будут показаны последние две цифры 4-значного IP-адреса. Объедините это значение со значением, указанным в части 1 IP адреса, чтобы знать полный
адрес.
Вы можете ввести полное значение в свой браузер, чтобы подключиться к WiFi модулю. Вы должны удалить все незначащие «0» . Если вы получите «192.168.001.106», то следует понимать это как «192.168.1.106» и именно этот адресс вводить в адресную строку браузера. Пример:
«001,106»
Скорость Частота обновления дисплея. Обычно около 100 Гц. Пример:
“01:02:04”
Режим настройки
Чтобы войти в режим настройки удерживайте кнопку более 1 секунды («среднее нажатие»). Подсветка начнет мигать белым цветом. Количество последовательных вспышек указывает на режим в котором вы находитесь. Каждое нажатие на кнопку более 1 секунды вызывает переход к следующему параметру.
Чтобы выйти из режима настройки, прежде чем переходить ко всем параметрам, нажмите кнопку более чем на 2 секунды («длительное нажатие»). Светодиоды подсветки вернутся к нормальной работе.
Другим способом выхода является полный перебор всех параметров настройки, после чего вы вернетесь к режиму отображения времени.
Чтобы изменить параметр нажмите на кнопку в течении менее одной секунды, а затем отпустите ее.
Режим Описание Значение
Режим отображения времени. Это обычный режим работы часов. В этом режиме короткое нажатие циклически переходит к значениям, указанным в таблице раздела «Режим отображения времени», но всегда возвращается к стандарту после 5 секунд бездействия.
Установка времени и даты
Обратите внимание, что настройки времени и даты не будут отображаться, если активен WiFi-модуль!
Установка часов. Каждое короткое нажатие увеличивает значение на единицу. При достижении 12 или 24 будет переход до 0.
(В зависимости от формата отображения 12/24 часов).
Примечание: коректируемый параметр выделяется повышенной яркостью.
Установка минут. Каждое короткое нажатие увеличивает значение на единицу.
При достижении 59 минут будет переход до 0. Каждый раз, когда вы устанавливаете минуту, секунды сбрасываются в 0.
Примечание: коректируемый параметр выделяется повышенной яркостью.
Сброс секунд. Каждое короткое нажатие сбрасывает секунды в 0, без изменения часов или минут.
Установка числа. Каждое короткое нажатие увеличивает значение на единицу. При достижении максимального числа дней в месяце значение возвращается к единице.
Примечание: коректируемый параметр выделяется повышенной яркостью.
Установка месяца. Каждое короткое нажатие увеличивает значение на единицу. При достижении 12 переход к единице.
Примечание: коректируемый параметр выделяется повышенной яркостью.
Установка года. Каждое короткое нажатие увеличивает значение на единицу. При достижении 2099 года будет переход к 2015 году.
Примечание: коректируемый параметр выделяется повышенной яркостью.
Мигающее число
Базовые настройки
0 Режим отображения 12\24 часов
«1» = 12
«0» = 24
Default: 0
1 Гашение незначащего ноля в разряде десятков часов. «1» = гашение
«0» = индикация
Default: 0
2 Эффект прокрутки цифр на дисплее при переходе от «9» до «0» в соответствующем разряде. “1” = есть
“0” = нет
Default: 0
3 Использование плавного перехода между цифрами. “1” = есть
“0” = нет
Default: 1
4 Формат даты. “0” = YY.MM.DD
“1” = MM.DD.YY
“2” = DD.MM.YY
Default: 2
5 Настройка гашения дисплея для увеличения ресурса ламп. Ресурс ламп не меньше 30000 часов или 15000 для ИН1 если над ними не издеваться. Если часы выключились понажимать коротко на кнопку.
Опции:
• «4» = «часы»: гашение в указанные часы каждый день.
• «5» = «часы и выходные»: гашение на весь день на выходные и в указанные часы в любой другой день.
• «6» = «часы и дни недели»: гашение на весь день в указанные дни недели а также гашение в указанные часы в
в любой другой день.
• «7» = «часы по выходным»: гашение в указанные часы по выходным.
• «8» = «часы в рабочие дни»: гашение в указанные часы в рабочие дни.
Примечание: если установлено “0”,”1″,”2″,”3″ сразу переход в режим 7
“0” = не гасить
«1» = выходные
«2» = раб.дни
«3» = всегда
“4” = часы
“5” = часы и
выходные дни
«6» = часы и дни недели
“7” = часы по
выходным
«8» = часы в раб.дни
Default: 0
6 Установка времени при котором будет произведено гашение индикатора. Default: 00
7 Установка времени включения индикатора. Default: 07
8 Ночной режим антиотравления катодов ACP.
В режиме антиотравления происходит перебор цифр при большой яркости дисплея. Если это вас беспокоит ночью , то этот режим можно отключить когда фоторезистор затемнен. «1» = не использовать ACP при затемнении
“0” = ACP
всегда используется
Default: 1
Настройки специальных эффектов
9 Использование сигнала фоторезистора. Если вы отключите сигнал дисплей всегда будет работать на максимальной яркости. “1” = есть
“0” = нет
Default: 1
10 Ночной режим. Вы можете выбрать режим уменьшения яркости для ламп, светодиодов подсветки или же ламп и светодиодов вместе. “0” = лампы
“1” = св. диоды
“2” = лампы и
св. диоды
Default: 2 установлено 2 и пока подсветка не используется ( можно поставить я экономлю энергию)
11 Увеличение значения для параметра скорости затухания при изменении цифр на индикаторе. Чем больше значение тем дольше переход между цифрами. Default: 50
Max: 200
Min: 20
12 Уменьшение значения для параметра скорости затухания при изменении цифр на индикаторе. Чем меньше значение тем быстрее цифры сменяют друг друга. Default: 45 ** 49 соответствует 1 секунде а если включены все эффекты то 46
Max: 200
Min: 20
13 Эффект прокрутки цифр на дисплее: с каждым коротким нажатием скорость уменьшается. Default: 4 – 6
Max: 40
Min: 1
14 Эффект прокрутки цифр на дисплее: с каждым коротким нажатием скорость увеличивается. Default: 4
Max: 40
Min: 1
15 Показ даты раз в минуту в течение примерно 5 секунд. “1” = есть
“0” = нет
Default: 1
Настройки режимов подсветки
16 Режим RGB подсветки.
Режим «Фиксированный» отобразит цвет подсветки в соответствии с уровнем интенсивности красного, зеленого и синего каналов заданных в режимах 9,10,11.
«Импульс» пульсация в секундном режиме с учетом уровней интенсивности красного, зеленого и синего каналов заданных в режимах 9,10,11.
«Цикл» перебор цвета подсветки случайным образом без учета уровней интенсивности красного, зеленого и синего каналов заданных в режимах 9,10,11. Режимы 13, 14, 15 будут пропущены, если выбран режим цикла.
Опции «0», «1» и «2» не используют функцию уменьшения яркости подсветки при затемнении фоторезистора (Ум яр.).
Опции «3», «4» и «5» используют Ум яр. «0» = фиксир.
“1” = импульс
«2» = цикл
“3” =фикс. / Ум яр.
“4” = импульс / Ум яр.
“5” = Цикл / Ум яр.
Default: 0
17 Интенсивность красного канала. Интенсивность будет уменьшена в соответствии с уровнем затемнения дисплея (фоторезистора). Если выбран режим цикла, этот параметр будет пропущен. Default: 15
Max: 15
Min: 0
18 Интенсивность зеленого канала. Интенсивность будет уменьшена в соответствии с уровнем затемнения дисплея (фоторезистора). Если выбран режим цикла, этот параметр будет пропущен. Default: 0
Max: 15
Min: 0
19 Интенсивность синего канала. Интенсивность будет уменьшена в соответствии с уровнем затемнения дисплея (фоторезистора). Если выбран режим цикла, этот параметр будет пропущен. Default: 0
Max: 15
Min: 0
20 Скорость перебора цвета подсветки если вы находитесь в режиме цикла. Чем выше число тем медленнее будут меняться цвета. Default: 10
Max: 64
Min: 4
Настройки ВВ генератора HV (см. Примечание «HV настройки»)
21 Каждое нажатие увеличивает напряжение ВВ генератора на 5В. Default: 180 если генератором управляет Ардуино.
Max: 200
Min: 150
22 Каждое нажатие уменшает напряжение ВВ генератора на 5В. Default: 180 Если mc34063 то при напряжении 1,25 вольт на 5 выводе на анодах ламп 185 вольт, а на декатроне 570 вольт. При 230 вольтах лампы начинают светиться сами.
Max: 200
Min: 150
23 Увеличение ширины импульса генератора ШИМ (PWM). Обычно этот параметр не следует изменять. Подстройка может понадобится при шумах ВВ генератора или применении необычных ламп. Default: 150
Max: 50
Min: 500
24 Уменьшение ширины импульса генератора ШИМ (PWM). Обычно этот параметр не следует изменять. Подстройка может понадобится при шумах ВВ генератора или применении необычных ламп. Default: 150
Max: 50
Min: 500
25 Увеличить минимальный уровень яркости когда часы полностью затемнены. Default: 100 .. 30-50
Max: 500
Min: 100
26 Уменьшить минимальный уровень яркости когда часы полностью затемнены. Default: 100
Max: 500
Min: 100
27 Увеличить число. Этот параметр уменьшает «ореол». Это связано с переходными процессами при переключении. Default: 0
Max: 50
Min: 0
28 Уменьшить число. Этот параметр уменьшает «ореол». Это связано с переходными процессами при переключении. Default: 0
Max: 50
Min: 0
Информационные сообщения
29 Текущая температура внутри корпуса. Значение равно 0 если модуль RTC не установлен
30 Версия прошивки
Тест дисплея. Перебор всех цифр во всех разрядах дисплея для проверки работоспособности ламп.
Примечание: «Настройки HV»: после настройки параметров ВВ генератора убедитесь что ни MOSFET ни регулятор напряжения не слишком горячие. Если любой из этих компонентов слишком горячий, либо снова настройте параметры ВВ генератора, либо добавьте радиатор.
Режим гашения дисплея
При выборе режимов гашения дисплея лампы будут отключены (ВВ генератор отключается) в зависимости от настроек, но светодиоды будут продолжать работать как обычно, сообщая вам что часы работают нормально.
Вы можете настроить гашение ламп в выходные дни, в будние дни или работу без гашения (по умолчанию). Также вы можете определить часы, в течение которых лампы будут погашены.
Например у меня есть настройка при которой часы погашены в будние дни с 7:00 до 16:00 пока я на работе. В выходные дни дисплей работает все время.
Вы также можете посмотреть время при погашенном дисплее. Для этого нужно нажать кнопку. Нажатие кнопки включает дисплей на время около минуты. Если вы нажмете кнопку несколько раз в течение 5 секунд время отображения увеличится:
• 1 нажатие: 60 секунд
• 2 нажатия: 1 час
• 3 нажатия: 4 часа
Режим восстановления ламп
После длительного периода работы свечение вокруг катодов ламп, которые не часто используются (например «9» на десятках часов или минут) может быть тусклым несмотря на то что антиотравление ACP регулярно выполняется. Если вы нажмете кнопку более 8 секунд, «длинное» нажатие, часы войдут в режим восстановления катодов. Вся мощность будет приложена к катоду одной цифры одной лампы чтобы очистить его. Короткое нажатие на кнопку изменит выбранную цифру. Еще одно сверхдолгое нажатие или перебор всех катодов во всех лампах вернет часы в нормальный режим.
Внимание! Не оставляйте катод в этом состоянии в течение длительного периода времени. Это тяжелый режим и он может повредить лампу если вы оставите ее в этом режиме слишком долго. Обычно нужно несколько секунд чтобы восстановить цифру катода. Обычно вам не нужно использовать этот режим! Это только для ламп в которых катоды уже отравлены. Не злоупотребляйте этим режимом!
Сброс к заводским настройкам
Чтобы вернуть часы в исходные настройки нажмите и удерживайте кнопку во время включения. Светодиоды будут быстро мигать “стробоскоп” для сигнализации того что сброс сделан. Вместо светодиодов если они не запаяны на всех лампах включатся цифры с 0 до 9. Исходное состояние есть смысл поправить в программе под самый оптимальный режим, например задать 45 ступенек плавного переключения цифр.
Все будет возвращено в исходное состояние по умолчанию и часы вернутся в режим запуска.
Внешний источник питания
Идеальное напряжение внешнего источника питания – 12V постоянного тока. Если напряжение больше 12 В потребуется регулировка ВВ генератора. Не рекомендуется использовать более 12 В. Абсолютно максимально допустимое напряжение – 16 В постоянного тока. Более высокое напряжение несомненно повредит часы. Крайний предел 40 вольт но это потребует перепайки входного конденсатора на такое же напряжение.
Ток потребления от источника 300 ма при всех включенных лампах и декатроне. Дла программирования Ардуино достаточно любую плату соединить разьемом usb к компьютеру. Напряжение литиевой батареи cr2032 часовой – 3,3 вольта, в схеме установлены 2 диода для питания часовой микросхемы от 5 вольт и от батареи. Проверить обязательно что не используется цепь заряда батарейки другого типа – особенно если часовая микросхема идет в составе модуля – отсоединить от батареи цепь из резистора 200 ом и диодика к +5 вольтам.
Revisions:
V0047: 22Jun2017: Split user manual and construction manual
V0048: 16Jul2017: Update for V48.
Перевод Панченко А.Ф.
5V (!) Avoid this pin а также 12 и 220 вольт и особенно если выше. Маленькие хитрости. это не получится поискать даже во вредных советах, может приходит с опытом. Аккуратность не помешает. В любом случае болтающиеся и замыкающие куда попало провода это неправильно. Проверить если надо заизолировать все провода и дорожки на плате по питанию, а то придется все ремотировать. соединения перед включением прозвонить. На щупы тестера напаять кусочки с половину иголки или булавки. На советской цешке нижний щуп плюс если мерять омы. Включать тестер надо на измерение диодиков а провода питания – проверять на единицах ом. Схема относится к логике. При проверке логики смотреть можно осциллографом сигналы, здесь при работе не должно быть – третьего состояния. Что это такое – выход микросхемы устанавливается либо в ноль то есть меньше полвольта либо в единицу – от 3 до 5 вольт. Все что между этим – в логике третье состояние. Оно есть во всех современных чипах, включая ардуино, это отключенный выход. Но при работе чаще всего неисправность либо замыкание. При включении можно посмотреть осциллой на выходах регистров – вот это есть на видео – выход устанавливается на полсекунды в 2 вольта. В этой схеме полсекунды – ардуинка медленная, а так время перехода 3 – 15 наносекунд в зависимости от серии логики . Все есть в тех описании национальных полупроводников за 1974 год. Вся логика американская но с 80-х делалась и в СССР с полным совпадением и даже более быстрые серии – все есть где прочитать – например sn74ls полностью повторяет Минская серия К555. Смотрите на видео светодиодную линейку – схема светодиодной линейки- она заменяет 8 канальный логический анализатор за 3800 долларов и можно уловить глазами частоту до 5 килогерц+ * а то и побольше на 2 порядка.
Про электро безопасность читаем в книжках. Если непонятно как подключить Ардуино.. по шагам – компьютер с виндой 10-кой или windows7 , с портами usb . Очень желательно параллельный порт LPT но для него надо покупать не новый ноутбук 2008 года не позже. Или системник такой же. программу и библиотеки с интернета поиск ардуино скетч sketch. Если нихт ферштейн это самое главное – курсы английского И немецкого немножко И по французски. Скоро 4-й язык добавится – уже надо несколько иероглифов знать, как будет честный продавец и хороший товар и еще пару слов по китайски.
Кое что по программным глюкам и аппаратным есть в коде программ. Например что чип ds3231 не выдает температуру и не устанавливает время если нет второго питания с батареи 3 вольта – надо поставить батарейку. И что его подтягивающий резистор на лапку сброса н е меньше чем 100 килоом – с чем это связано трудно сказать но если поставить 4к7 то глючит.330k на фото. * можно не устанавливать он за год посадит батарейку если не включено питание. Код программы изменяется прямо в Ардуино оболочке но удобнее использовать git и не только – вот картинка редактора akelpad с 4 включенными дополнениями для программиста – подсветка кода и выделение кусочков программы – а фигурные скобочки правильно? И еще на винде есть total commander со сравнением файлов по символам или байтам, а здесь на линухе убунту есть meld.
а это схема на ИВ-22 . Люминесцентные индикаторы зеленого свечения тоже красиво смотрятся и их целый пакет из под молока в шкафу.и еще одна конструкция часы на ИВ-12. Только у них чуть больше потребление мощности, надо розетку, там накал у лампочек, 1.3 вольта 52 мА правда у каждой. На ИНках работает сутки даже без 220 вольт, от ноутбучной батареи.. мощность даже меньше если по схеме правильно все, полтора ватта а не 2. Для ИВ-22 подойдет с малой переделкой программа от 7 -сегментных индикаторов.

ссылки Метеостанция предсказатель погоды project Modular Weather Station .
волюметер vu-meter с использованием ИН-13 .. покупал парочку на Толкучке у магазина радио на Шаболовке то ли у магазина у Маяковской она потом переместилась ближе к нам на Покровско-Стрешнево, Тушинский рынок и потом в Митино. Это был 1988 год примерно, не наверно 1986 уже были микро 80 и радио 86 рк но до Синклера и Z80
vu-meter на декатроне.
Эффект на полиатроне А201.
Магический глаз magic eye . 2 варианта зеленого огонька от магнитофона или приемника, на китайской лампе и советской.
Часы на одном декатроне А101 . Светящиеся точки соответствуют 3 стрелкам часов, можно сделать и на других ОГ4 например но сложнее.
обжигалка и летящие провода медный с обмотки пэв 2


Силовая техника – запуск дизеля 4.7 киловатт 7.3 hp или 12 кВт V2 если все аккумуляторы разрядились. Ардуинка или stm8 . Сложного ничего нет. понадобится вот –http://www.count-zero.ru/2018/stm8_wakeup/ и https://hw-by-design.blogspot.com/2018/10/stm8-timer.html Отлавливается уровень напряжения ниже 3.2 вольта хотя бы на одной сборке. Через катушечку для развязки сигнал приходит на плату управления, выдается последовательность для запуска станции. Если станция заработала то заряжаются аккумуляторы, после работает еще 5 – 20 минут если запрограммировано, потом выключается. Дизель останавливается релюшкой от машины – реле света – которая отключает 12 вольт от клапана, там просто на пружинке электромагнит, без подачи напряжения перекрывает подачу топлива. мотор Yanmar L100AE китайского завода очень мощный для лодки мини трактора или мотопомпы, на нем катушка генератора с обмоткой 22 или 50 ампер 220 вольт.
Декатрон применялся для точечной сварки – ставилось число импульсов сколько надо подать для большей или меньшей мощности. и для счетчика импульсов радиации – бегущий огонь по кругу это знак опасности, одеть средства защиты!
еще конструкции – фонарики, цветовой индикатор громкости звука – рядом с колонкой если то показывает музыку разными вспышками.
https://yahobby.ru/webdirectory/88898/%d1%84%d0%be%d0%bd%d0%b0%d1%80%d0%b8%d0%ba-%d0%bd%d0%b0-%d1%81%d0%b2%d0%b5%d1%82%d0%be%d0%b4%d0%b8%d0%be%d0%b4%d0%b5-3/переносная светодиодная лампа высокой яркости, на 20-ваттном кристалле с керамической подложкой. Кристалл белым светом светит – хорошо для фото и видео. Ставим 2 штуки – лучше чем лайтбокс. 3 более слабых режима 0,8 и 3 и 8 ватт – попробую в пещере – съемка видео на камеру, можно и надеть на шею или взять зубами за ремешок – будет ходовой свет. Как налобник тяжеловата, 8 аккумуляторов или 4 18650.
с похожей схемой – инвертор для загородного дома, есть большой чтобы включить розетки от аккумуляторов а есть поменьше только на лампочки ноутбук или телевизор и маленький холодильник.
От солнечной батареи зарядка – 60 ампер 14 вольт а батарея 36 вольт, тоже незаметная схема – преобразователь с повышением напряжения.
будет раздел Немножко звуковой техники вот там как раз усилитель на комплементарной паре – и большой усилитель где регулятор сделан на коммутаторах К590КН1 – в тяжелые времена 90-е годы купили такой за 500 долларов – там вместо щелкающей крутилки 2 кнопочки – как сейчас во многих современных устройствах . нажал 1 раз (не нажал а только дотронулся – схема сенсора на 35 мегагерц генераторе – используется легендарная схема К155ЛА3 2И-НЕ). Это сейчас такие кнопочки в трамваях и светодиоды а тогда все только самые первые образцы были. Музыкальный синтезатор как в первых компьютерах Синклер AY-3-8910 с разными эффектами только от микроконтроллера. (а чего бы сам Синклер Ленинградский не повторить?? тем более автор в сети есть)
а это на 8051 микроконтроллере. Только на сильно современном из Китая. ( это который умельцы разобрали и срисовали по слоям – где то на заводе, а потом делали без названия, там и защиты могли снять с программ. Не рассчитывайте на залочку программ – снять и все считать надо 15 минут и какой то стм советский то ли китайский, надо дать на разборку 3 чипа с программой и пришлют гекс или бин, за не очень дорого. Умельцы еще и на 155ЛА3 припаивали куда то проводок с сопротивлением 10 ом, тогда защита обходилась, сейчас есть какой то свисток http://chipwhispererи не один вроде продается. Автор этой статьи в 1989 заменил тактовый от материнки компа взяв 4 штуки логики, его работа была расшифрована на маленьком стенде подавая разные импульсы и смотря что на выходе. из приборов линейка светодиодов и все.)
Пошарашил за лампами. Рыська скинула с полочки – все часы хоть бы что, а вот одна лампочка ИН -1 околела от сильного удара, там электроды, оказывается, замыкают. Заменю на новую, хотя – можно сильно постучать – цифры загораются. Из – за замыкания подсело напряжение у импульсного блока, Оказывается, микрухи К155ИД1 – работают от 3,5 вольт питания – совершенно нормально, и лампы ИН-1 – светятся, если 78 – 90 вольт всего (ставил 170 подстроечником, с резисторами 15к, схема управления подает короткие импульсы – там ардуинка. В длительном режиме советуют 160 вольт и 30 килоом.)
Рысячья зверюга извиняется – подошла, облизала ухо, да ну, пырыс Кошака вроде по-марийски. Собачища у нас Алтын – Золото по крымско – татарски и в древней Булгарии, ну по-татарски. На поволжски – Сарынь (не надо обижать нашу диаспору плохим царским названием – Морды типа широкие, Меря – можно – по – франкски, словацки! Мари – можно – Воин, Муж по древне – ирански и его мама у Французи.. мордва неправильно называть. Эрзя, Мещера, Черемисы, Мокша – правильно. А лучше – Русские, Великороссы.)
zpool create lynx raidz1 /dev/… мало места, подключил 6 дисков винчестерских, по 2 тб лучше, чем по 3 – не так греются.
рабочая схема часов на индикаторах ГРИ, программирование, применение счетной лампы декатрона, плазменные часы,часы на ИН1 А101 А107 ОГ4 ИН12 ИН16 ИН14
комментарий к источнику высокого напряжения – если он на Мотороле 34063
C2=979 пФ
Ipk=472 мA
R3=0.635 Ом
L1min=570 мкГн
C3=2 мкФ
R4=180 Ohm
R1=2.2k R2=910k (518.3В)
конечно 2 обмотки а не дроссель, микросхема на 40 вольт рассчитана
Опять по источнику. подглядел на известном форуме, сейчас конечно программы и компы меньше сложностей вызывают.. чем 3 транзистора по схеме Дарлингтона. Русских понятий маловато, составные транзисторы. (не волюметр а индикатор громкости, стоит на приборной панели самолета а не эйрлайнера и не апает а увеличивает..)
“Вот хочу это сделать от юсб usb smd чтобы все было и помещалось внутри флешки, катушку только на плоском стерженьке феррита как намотать”
Катушка подходит кольцо по рассчету альсифер 0.8 см в квадрате, ток импульса до 14 ампер напряжение 3 вольта, для открытия полевика 12 вольт со второй микросхемы, через 2 транзистора. Полевик на 40 миллиом, на 7 вольт порог, на 50 ампер, советский с содержанием золота. Схема укорачивания импульса, еще 2 транзистора или 1 с диодом Шоттки. Да, 2 обмотки толстым проводом медным и очень толстым в 3 провода 4 витка и 200. В корпус от источника ноутбука войдет, если очень плотным объемным монтажем, радиатор транзистора и силового диода половину места займет.
Так что от 12 вольт обычная схема на китайской плате это лучшее решение, 2 транзистора подпаять! SMD дроссель там полтора сантиметра на сантиметр и толстым проводком, 500 микрогенри. И это от 12 вольт. Чтобы проверить подходит дроссель или насыщается нужен осциллограф. Подключить его выводы к резистору по питанию перед дросселем, не больше чем 0.2 ома и 2 ватта. Если будет форма сигнала без резкого выброса – пила называется, резистор измеряет ток через дроссель, то все правильно, если ток резко возрастает в виде короткого всплеска – дроссель насыщается и не подходит.
програмки есть во вложенияхъ
пока текст статьи часто редактируется – может быть испорченый код , особенно символы >> < ^%&
[…] Сделайте светодиодную линейку. в другой конструкции. https://yahobby.ru/%D1%87%D0%B0%D1%81%D1%8B-%D0%BD%D0%B0-%D1%86%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D1%8B%… […]
на первой картинке. Декатрон установлен в часах, он дает просто эффект для красоты – пружинка Слинки. Этот прибор как неоновая лампа, только счетчик импульсов и показывает сразу сколько их было. Работал в связке со счетчиком Гейгера, если огонек быстро перемещается по кругу и проходит 5 импульсов за секунду – загорается неонка Внимание Радиация! Если огонек несется по кругу то срочно в укрытие, чем быстрее тем лучше. а вот здесь мирное применение.
без всяких обсуждений, сейчас скорее всего пригодится. Подвал ослабляет радиацию в 10 раз, метро или бункер в 1000 раз. У кого нет дозиметра помрет от непонятно чего так что есть смысл срочно купить.