Часы на цифровых лампах

еще обсуждение с форума по покупкам в интернет. (поиск – часы на ИН-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 topicnext 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

  • Last Edit: January 01, 1970, 01:00:00 am by Guest

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 или поли метил метакрилат оно же
а извиняюсь за французи на х .. вообще корпус.. Это вот не меньше искусство. Фонарик у меня налобник такой же который на 900 люмен 3 часа.
Flyback Converters for Dummies я все таки переведу как нибудь ну прямо учебник из МАИ.. Преобразователь напряжения обратного хода начинающим и мастерам. A simple flyback converter high voltage power supply for NIXIE tubes. Ronald Dekker Special thanks to Frans Schoofs, who really understands how flyback converters work introduction What you need to know about inductors The boost converter A simple boost converter high voltage supply for NIXIEs An inductor test bench What you need to know about transformers The flyback converter A flyback converter high voltage supply for NIXIEs back to homepage If you are interested in Flyback Converters you might want to keep track of my present project: the µTracer: a miniature radio-tube curve-tracer Click here to read about my “low-noise” 6 to 90 V converter project which replaces the anode battery in battery tube receivers. introduction In the NIXIE clocks that I have built, I did not want to have the big and ugly mains transformer in the actual clock itself. Instead I use an AC adapter that fits into the mains wall plug. This means that I have to use some sort of an up-converter to generate the 180V anode supply for the NIXIEs. This page describes a simple boost converter and a more efficient flyback converter both of which can be used as a high voltage power supply for a 6 NIXIE tube display. Frans Schoofs beautifully explained to me the working of the flyback converter and much of what he explained to me you find reflected on this page. I additionally explain the essentials of inductors and transformers that you need to know. This is just a practical guide to get you going, it is not a scientific treatise on the topic. to top of page back to homepage What you need to know about inductors Consider the simple circuit consisting of a battery connected to an inductor with inductance L and resistance R (Fig. 1). When the battery is connected to the inductor, the current does not immediately change from zero to its maximum value V/R. The law of electromagnetic induction, Faraday’s law prevents this. What happens instead is the following. As the current increases with time, the magnetic flux through this loop proportional to this current increases. The increasing flux induces an e.m.f. in the circuit that opposes the change in magnetic flux. By Lenz’s law, the induced electric field in the loop must therefore be opposite to the direction of the current. As the magnitude of the current increases, the rate of the increase lessens and hence the induced e.m.f. decreases. This opposing e.m.f. results in a linear increase in current at a rate I=(V/L)*t. The increase in current will finally stop when it becomes limited through the series resistance of the inductor. At that moment the amount of magnetic energy stored in the inductor amounts to E=0.5*L*I*I. Figure 1 In words: the inductor does not allow for any abrupt changes in the current. When a change in applied voltage occurs, the inductor will always generate an e.m.f. that counteracts this change. When the circuit is interrupted for instance, the inductor will still try to maintain the current flowing by generating a very high voltage over its terminals. Usually this will result in a spark in which the magnetic energy stored in the inductor is released. This particular behavior of inductors is used in boost converters to boost the voltage to levels above the battery voltage. Materials like ferrites can be used to increase the magnetic flux in an inductor. When a magnetic field is applied to a ferrite the small magnetic domains in the ferrite will align with this field and increase its magnitude. In this way inductors can be made smaller and with lesser turns and thus with smaller series resistances (smaller losses). Note that the flipping of these domains costs some energy, but in good ferrites this can be very small. With increasing magnetic flux more and more magnetic domains point into the direction of the field. At a certain point all the magnetic domains point into the direction of the field and at that point we say that the ferrite saturates. Any further increase in current will only result in a small increase of flux, basically as if the ferrite was not present. Since most ferrites have a very high permeability, already small currents can result in a high magnetic flux. As a result the ferrite will saturate at a current which is not practical for power conversion applications Ferrite cores for inductors and transformers for power applications therefore have an air gap. An air gap reduces the effective permeability and thus the magnetic flux. The larger the air gap, the stronger the reduction in flux an the higher the maximum current the inductor can handle. We say that the magnetic energy is stored in the air gap. The photograph shows several inductors for DC/DC converters salvaged from old PCBs from PCs, Laptops etc. If you consider playing with DC/DC converters it is best to buy at least one decent inductor with a known inductance, series resistance and maximum current. The inductor in front of the picture is the 100uH “reference” inductor I use. to top of page back to homepage The boost converter The boost converter is perhaps the simplest of all switched mode converters. It uses a single inductor without the need for “difficult” transformers. It’s working can best be explained with the simplified circuit diagram given in Fig. 2. Here the transistor is represented by an ideal switch and the control circuitry has been omitted. The dissipation by the NIXIE tubes is represented by the load resistor Rload. A high voltage capacitor C is used to buffer the output voltage. In a typical configuration the input voltage would be something like Vbat=12V and the output voltage Vout=180V. Figure 2 Simplified circuit diagram of a boost converter. At t=0 the switch closes (Fig. 2A). As a result the current through the inductor will start to increase linearly according to I=(Vbat/L)*t. At a certain moment the switch is opened by the control circuit (Fig. 2B). The current at that monent has reached a certain value Ipeak. We have seen in the previous section that the inductor wants to keep the current flowing through it’s windings constant, whatever it takes. The switch is open, so the only way the inductor can achieve this is to forward bias diode D so that the current (and thus the energy) can be dumped in the buffer capacitor C. Now remember that the capacitor was charged to 180V! So in order to forward bias the diode, the inductor has to generate an e.m.f. (or induction voltage) of something like 180-12=168V., something like a “controlled spark. The current now quickly drops according to I=Ipeak-(Vout/L)*t. For Vbat=12V and Vout=180V this means that it will take only a fifteenth (180/12) of the time it took to reach Ipeak when the switch was closed, to drop again from Ipeak to 0 now the switch is open. After a certain time the whole process repeats at a rate of f times per second. So far so good. However, the boost converter has a serious disadvantage. To understand this we first have to consider the switch that we have been using. In a real circuit most likely a power MOS transistor will be used as the switching element. In the boost converter this transistor will have to handle both a high current when the switch is closed and a high blocking voltage when the switch is open! For the transistor this is a difficult combination. In order to make the transistor withstand high blocking voltages, the manufacturer of the transistor has to include regions in the transistor that will accommodate these voltages so that the intrinsic transistor will not breakdown. However, when the switch is closed (transistor conducting), these regions will result in additional parasitic series resistances and thus in an increased Ron. This is the reason why transistors with a high breakdown voltage always have a higher Ron than transistors with a lower breakdown voltage. Since the currents can be quite high, this inevitably means losses in the form of dissipation in the transistor. As we will see in one of the next sections this problem is solved in the fly-back converter by the use of a transformer. By balancing the amount of power stored in the inductor to the amount of power dissipated in the load it is possible the calculate the output voltage of the boost converter. Every second the amount of power dissipated by the load is: If T is the total cycle time, and x the fraction of T that the switch is closed, then the maximum current in the inductor is: The energy per package delivered by the inductor is: In one second f=1/T packages are delivered so the amount of energy delivered per second is: Since in steady-state the amount of energy delivered should equal the amount of energy used [1]=[2]: to top of page back to homepage A simple boost converter high voltage supply for NIXIEs If you want to build a simple DC/DC converter to lighten up your NIXIEs and you don’t care to much about the conversion efficiency, even if it means a (small) heatsink for the power transistor, then the boost converter is the best choice. But even if you think of building a real fly-back converter than it is a good idea to start with a simple boost converter. The boost converter only requires an “of the shelf” inductor and when you have it working it is easily converted into a fly-back converter by a few small modifications. Figure 3 Simple 12-180V boost converter using the 555 as controller. The circuit is very simple and closely follows the circuit topology of Fig. 2. For the transistor I have used a BUZ41A. This transistor is rated at a maximum Vds=500V and an on resistance of 1.5ohm at 4.5A. Equivalent or better types like the IRF730 will also perform well. The diode should be a fast switching type like the BYW95C or better. An old (computer) power supply will yield you most of these components. The inductor I picked from a catalogue and is 100µH with a few tenths of an ohm series resistance capable of handling several Amps of current. The most interesting aspect of the circuit is how an ordinary 555 is used to regulate the output voltage. Now, there are hundreds of switched mode controllers ICs on the market which are all better suited for this job than the 555. The problem with all these ICs is that if you build a nice NIXIE clock using them, and at one moment in the future the IC breaks down, it is more than likely that it is already obsolete and out of production. The 555 is (very) cheap, performs well enough and most likely will remain in production forever. To understand how the controller works it is best to first understand how the 555 functions. On the internet you may find a number of excellent 555 tutorials [1,2]. Without R3 and T1 the 555 is configured as a normal astable multivibrator running at a frequency of: Without any feedback, the output voltage at this frequency will be well in excess of 200V. However, the voltage divider formed by R4, R5 and R6 has been designed and adjusted in such a way that when the output voltage reaches 180 V, T1 just starts to conduct. This is at a base-emitter voltage of ca. 0.8V. Now remember that the 555 works by charging and discharging the capacitor between 1/3Vcc and 2/3Vcc as defined by an internal resistor ladder network. When T1 starts to conduct it will pull down the internal supply voltage of this network resulting in a smaller voltage swing and hence a higher frequency. From the last equation in the previous section we learn that a higher frequency (smaller T) will result in a lower output voltage. In this way the output voltage will settle at a value determined by R5. For T1 I have used a high voltage type. There is really no need for that and any small signal npn transistor with a decent gain will work. A drawback of such a simple controller is that the circuit has no protection at all against short circuits or overload situations. An accidental short circuit of the output will therefore always result in a defect power transistor (as I have experienced quite a number of times). Figure 4 Testing the boost converter using a dummy load (and one NIXIE). If you are in the testing phase, and do not want to connect the power supply to the NIXIEs yet, it is best to connect a dummy load to the output since the circuit is not designed to work without a load. I always first find out what the current is that I want to operate my NIXIEs on. I usually choose a value well below the operating condition specified in the datasheet. This will greatly extend the lifetime of the tubes. Using a high voltage supply I select the supply voltage and the load resistor in such a way that with a minimum of current the brightness of the tube is still good enough. Once the total current and the voltage are known an equivalent load resistor can be calculated from Rload=Vout/Itotal. During the testing phase this resistor connected to the output replaces the NIXIE tubes. A few words about safety. Although the 180 Volts are generated starting with an innocent 12 Volt an accidental contact with the charged buffer capacitor will be a painful, possibly a lethal experience. Always be very careful ! I always place a small neon indicator lamp at the output of the converter (even in the final clock) to clearly indicate that a dangerous voltage is present at the output. Additionally during testing I permanently have a 20kohm/V multi-meter connected to the output so that I always know the output voltage. Finally, the advice of my father who was from the radio tube area: always keep one hand in your pocket when touching the circuit when it is switched on. In that way the current can never pass your heart. to top of page back to homepage An inductor test bench When you want to start experimenting with boost or fly-back converters it is good idea to buy at least one inductor with known parameters that may act as a kind of reference device for the inductors or transformers that you make yourself. I use a 100µH inductor with about 0.2ohm series resistance capable of handling several Amps of current. It is especially designed for SMP applications. The circuit depicted in Fig. 5 allows you to compare “an unknown” inductor (or transformer) with the reference inductor. Figure 5 Circuit diagram of the inductor test bench. The circuit is designed to test the inductor as closely as possible under conditions that occur in the boost converter presented in the last section or in the fly-back converter to be presented in one of the next sections. Basically, the circuit is little more than the inductor which is connected to the 12V power supply by transistor T1. The current through the inductor is measured by the small series resistor R4. A voltage drop of 100mV over R4 corresponds to a current of approximately 1A. When the transistor is opened, the inductor can dump its energy in diode D3. Since the voltage drop over the diode is only 0.6V, it will take about 12/0.6=20 times as long for the current to drop to zero (remember I=(V.t)/L). This is the reason why the gate of the transistor is driven with a highly asymmetric signal generated by the oscillator around N1-N6. The transistor on-time is determined by C1 and R1+R2. R2 is set so that the transistor on-time is equal to the transistor on-time in the converter under normal load. The transistor off-time is determined by C1 and R3 and about a factor 20 longer than the on-time. Figure 6 The inductor test bench circuit (left) and a measurement off the reference inductor (right). In Fig. 6 (right) you find a measurement of the reference inductor. We find that with a supply voltage of 12V the current through the inductor reaches a value of I=V/R=0.361/0.11=3.28A in 27.1µs. Since I=(V/L)t we find for the inductance L=(V/I)t=(12/3.28)27.1=97.6µH. Not bad! At a little bit higher current we observe a sharp increase in the current through the inductor. This is the point where the ferrite saturates. The inductor should not be used beyond this point. You may now want to try different inductors e.g. inductors salvaged from old (computer) power supplies. Switch S1 make it easy to compare these inductors with the reference inductor. Another important parameter to watch is the current consumption of the test-bench. An increase in switching losses in the inductor core is reflected by an increase in power consumption. An alternative simple and quick way to measure the inductance of an unknown inductor can be found here. to top of page back to homepage What you need to know about transformers This section deals with a few basic things you need to know about transformers in order to understand fly-back converters. In Fig. 7 I have tried to sketch an elementary inductor and its schematic equivalent. Note that both windings have a certain direction and that equal directions are indicated by a dot. Figure 7 Basic transformer with open secondary windings In this example we assume that the primary side of the transformer has a certain number of turns with inductance L1. The secondary side of the transformer has ten times that number of turns. As a result the secondary side will have an inductance L2=10^2*L1=100*L1. First consider the case that the secondary windings are not connected. When a voltage source is connected to the primary coil the current through the primary winding will start to increase linearly at a rate I=(V/L1)*t. Since with open terminals at the secondary side no secondary current can flow, the transformer will behave as a normal inductor with inductance L1. The increasing primary current will generate a magnetic flux not only through the primary windings, but the same flux will also flow through the secondary windings. It is easy to see from reasons of symmetry that if the secondary coil would be identical to the primary coil the voltage at the primary and secondary side would be equal. In this case we have 10 times the number of turns at the secondary side. This can be seen as a series connection of 10 coils each carrying a voltage of 10V so that in total 100V is induced at the primary side. The voltage of 100V at the output remains as long as the current continues to increase linearly. In practice this means until the current reaches its compliance or until the core saturates. Figure 8 Basic transformer with closed secondary windings Next the secondary winding is connected to some load which will allow for a current to flow (Fig. 8). If the primary winding is now connected to some voltage source, a current through the primary winding will start to flow, resulting in magnetic flux in the direction as indicated by the arrow. This magnetic flux will obviously also flow through the secondary winding. We have seen that an inductor resists a change in magnetic flux. To counteract the increasing flux, a current flowing in opposite direction through the secondary winding will start to flow as indicated in Fig. 8 Resulting in a voltage drop over the load as indicated. Figure 9 The transformer in flyback Finally the voltage source at the primary side is suddenly removed (Fig. 9). The only way the secondary winding can prevent a sudden collapse of flux is to reverse the direction of the current flowing through the secondary winding. As a result alsothe voltage drop over the load will reverse. Note that the voltage over the load will increase to any value that is needed in order to maintain a constant flux. The magnetic energy stored in the inductor is dumped into the load and the secondary current decreases at a rate Vout/L2 to top of page back to homepage The flyback converter Figure 10 depicts the basic elements from the flyback converter. Again all control circuitry is omitted, and the switching MOSFET is represented by an ideal switch. Figure 10 Phase one, storing energy in the transformer. For the moment we assume that at t=0 the buffer capacitor is charged to the nominal output voltage Vout and that the current through the primary windings of the transformer is zero. At t=0 the switch closes and a current will start to flow through the primary winding. This will induce a voltage over the secondary winding with a polarity as indicated (see previous section). Since the diode is reverse biased no secondary current will flow, so basically the secondary winding is “not connected”. In other words at the primary side of the transformer we “just see an inductor”. As a result the primary current will start to increase lineary according to I=(12/L1)*t. During the time the switch is closed the voltage induced over the secondary windings will be n*12V. This means that the diode minimally has to block a reverse voltage of n*12+Vout Figure 11 Phase two, dumping the energy from the transformer into the buffer capacitor. At a certain moment the switch will open (Fig. 11). Lets call the current that was flowing through the primary winding at the moment just before the switch was opened Ipeak. The energy then stored at the moment of opening is 0.5*L1*(Ipeak*Ipeak). The transformer wants to sustain the magnetic flux. Since the circuit at primary side is open the only way the inductor can do this is by inducing a voltage at the secondary side high enough (>Vout) to forward bias the diode. The initial value of the current will be I2=Ipeak/n. During the time that the diode is forward biased, the voltage over the secondary winding will equal Vout+0.8V. The 0.8V is the voltage drop over the diode and can for a high output voltage like in a NIXIE converter be neglected. The transformer will transform this voltage down to Vout/n. So the total voltage that the switch has to block in open position is 12+(Vout/n). Actually this is the big advantage of a flyback converter over a boost converter. In a boost converter the switch (MOSFET) has to carry a large current during the on phase and a high voltage during the off phase. In the flyback converter the voltage during the off phase is transformed down to a value determined by the ratio in turns. This means that a MOSFET with a much lower Ron can be used (see section on the boostconverter). Similarly, in the boost converter the diode has to carry both the high on current and a high reverse voltage. In the flyback converter the diode at the secondary side only has to block a high voltage while the current is low (Ipeak/n). This makes it possible to select a diode with smaller capacitances and hence higher switching speed. All this results in reduced losses and an increased efficiency. Figure 12 Phase three, energy dump completed discharge of drain-source capacitor This continues until all energy stored in the transformer is dumped in the buffer capacitor. At that moment I2 becomes zero (Fig. 12). At that moment the e.m.f induced at the primary side (Vout/n) will vanish. However, the parasitic capacitance of the switch (source-drain capacitance of the MOSFET) will be charged to (Vout/n)+12 V. At the primary side now a series resonant tank is formed with a charged capacitor (Fig. 12 right). This will cause a dampened oscillation. Figure 13 Voltage over the switch during all three phases Figure 13 schematically shows the drain-source voltage (the voltage over the switch) during all the phases of the converter just described. During phase the switch is closed. What we see is the voltage drop over the switch caused by the non-zero on resistance. During this phase the current will increase linearly, so also the voltage drop over Ron will increase linearly. At point b the switch opens. The secondary current will start to flow and the output voltage wil appear down transformed over the primary winding. The total blocking voltage over the switch will be 12+(Vout/n) (Fig 13c). At point d all the energy is dumped in the capacitor and the secondary current drops to zero causing the induced e.m.f. at primary side to vanish. The charged drain-source capacitor, now suddenly connected in series with the inductance of the primary winding will result in a dampened oscillation (Fig. 12e). At point f the switch closes again, and any remaining energy in the LC tank will be dissipated in the transistor. Figure 14 Stray inductance. This leaves just one small phenomenon to be explained. No transformer is ideal. There will always be magnetic field lines generated by the primary windings which are not (fully) enclosed by the secondary windings. This will cause a stray inductance that can be modeled as a small inductor in series with the primary winding of the transformer (Fig. 14). We have seen that all the energy that is stored in the transformer is dumped in the buffer capacitor. This does not hold for the (small) amount of energy stored in the stray inductance. So the sudden opening of the switch will cause a sharp voltage peak, just as with any inductor which is suddenly disconnected from a DC current. The small stray inductor in series with the source-drain capacitance will cause a dampened high frequency oscillation (Fig. 15). Figure 15 High frequency oscillations due to energy stored in the stray inductance. If needed the switching transistor can be protected from the high voltage peak by an RC snubber network or a zenerdiode which limits the maximum source-drain voltage. Finally you can check for yourself the equation derived for the output voltage of the boost converter also holds for the flyback converter. This is not really surprising, like in the boost converter the flyback converter is based on the dumping of the energy from an inductor or the primary winding of a tranformer in the load. The transformer just serves to lower the voltage over the switch. to top of page back to homepage A flyback converter high voltage supply for NIXIEs. After all what has been said so far, the circuit diagram of the flyback converter will hold no surprises (Fig.16). Literally the only difference with the boost converter is that the inductor is replaced by a transformer, and that the transistor has been replaced for a BUZ21. The BUZ21 has a much lower on resistance (Ron=0.085 ohm) as compared to the BUZ41A (Ron=1.5 ohm) but also a lower drain-source breakdown voltage (100V versus 500V). Figure 16 Circuit diagram of the Flyback converter. The difficult part of the circuit is the transformer. Well it is not exactly difficult, but the problem is that you have to make it yourself. What makes things worse is that finding a suitable ferrite core can some times be difficult since component vendors often only have a few types on stock. The E-shape ferrite core that I use measures 20x20x5 mm (Fig. 16) I got them from Paul van de Broek who always helps me when I need something special. Figure 17 The ferrite core that I use (20x20x5 mm). So what is the strategy for finding the number of turns you need on the ferrite core that you have? Well first of all I always start with my inductor test-bench so that I can compare what I have made with the reference 100 µH inductor. If this is your first fly-back converter it might be illustrative to first try the ferrite core without an airgap. Mind everybody always says airgap, but what they actually mean is a spacer, often made from plastic (cellotape). So start with say 10 or 20 windings without an airgap. What you probably will see in the test-bench is a too high inductance (slower increase of current as compared to the 100 µH inductor). At the same time you will find the ferrite saturating at a low current. It is now time to include the spacer. Attach a peace of cello tape and cut the excess amount of tape with a razor blade so that only the touching surfaces of the ferrite are covered with tape. If you try the inductor now you will find a much lower inductance and a higher saturation current. Probably you will need to add or remove some turns to get an inductance of 100 µH (same slope). For the primary winding I use 0.4 (or 0.5) mm diameter insulated copper wire. When you have determined the proper number of primary turns, the secondary winding consists of ten times that number of turns. For the secondary windings I use something like 0.1-0.15 mm diameter wire. I always include a layer of tape in between two layers of secondary windings to prevent arcing. The transformers that I use have 22 primary turns and 220 secondary turns. Figure 18 Two examples of the Flyback converter built on a peace of breadboard. Figure 19 shows the drain-source voltage of power MOSFET measured with a 1:10 reduction probe. The 1- on the left axis marks the 0 V input level. The image is not very sharp due to some trigger jitter caused by a 50Hz ripple on the power supply. Nevertheless, several features from Fig. 15 can be recognized. The repetition frequency is 32 kHz and the maximum blocking voltage of the transistor is about 31 V according to theory. The voltage over the transistor almost swings for two full periods until the transistor switches on again. The high frequency oscillations due to the stray inductance are there, but difficult to see on the photograph. The increasing voltage drop over Ron during the on phase is clearly visible. Figure 19 Drain-source voltage of power MOSFET measured with a 1:10 reduction probe. The total converter can easily be built in an area of less than 4×4 cm. To increase the lifetime of my tubes I usually run them on as low as current as possible. Typically 1-1.5 mA. This means that the converter has to generate for 6 digits about 6 to 7 watts. The efficiency is ca. 80%. This is not spectacular but good enough for such a simple circuit. If you decide to built one: have fun, be careful and good luck! to top of page back to homepage Web links [1] http://www.williamson-labs.com/555-tutorial.htm [2] http://www.uoguelph.ca/~antoon/gadgets/555/555.html back to homepage

Полезные добавки в загрузках – прошивка , цоколевка ламп ИН-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А

Файл:Радио 1975 г. №05.djvu

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

Проект Разработка Настройка . Изделие Прошивка схемы и возможно платы. (не очень я их делаю если не надо вдруг больше 5 штук. Или вообще приспосабливаю готовые модули – в этом случае подходит как и с фонарем).

Вариант собрать все на железной логике и поставить часовой кварц 32767 герц.

Уже такие лежат на антресоли – спрятал их а то там корпус не очень красивый, листы оргалита и картонка, деушки выбросить могут . Логика и ИВЛ1-7/5 вроде как, не очень много корпусов. 30 лет работали и сейчас заработают если включить. Зеленое свечение люминофора вроде не ослабло .

Лампы ИН-14 in14 nixie tube 4 штуки и 2 in16 ИН-16 так красивее. Перевернутая двойка вместо пятерки в глаза не бросается.

можно почти не возиться с электроникой – припаять лампы или поставить в панельки. Адаптер на 12 вольт. Но что то с логикой работы не то – на ночь выключаются если режим такой, подсветка и установка времени по 3 кнопке. Задать время отключения не получилось. Зато есть регулировка первой клопкой режима против отравления, с 1 до 9 минут, вполне нормально 2 минуты. Случайно погорела ams1117 пришлось ремонтировать менять все 74hc595a а остальные чипы включая stm8s003f3 ds3231 кратковременно выдержали 12 вольт по питанию (с MC34063 очень вряд ли получится такое – там ставится резистор который ограничивает ток импульсов). Индуктор заметно греется да и полевик тоже, поменять надо бы катушку 470 микрогенри проводок что ли тонковатый или сердечник насыщается, от источника 4 ватта с половиной, лампы по 2миллиампера это еще и ток не постоянный ну меньше 2 ватт. Не вытерпел – добавил 2 транзистора перед полевиком – в рассчете электроники главное чтобы его делал химик бабах нет наверно электронщик Уууу тик так и никакого бух.

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

Схема. Поскольку работает от батареи – сейчас просто усиленная от ноутбука, а потом будет 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 виток.

понижающий вместо lm1117 – если он нужен конечно и питание от 12 вольт (а не от четвертинки батареи от Теслы электромобиля там 3.7 вольта 72 в параллель). Переходим на литий и сборки из 18650 и это не шутка. Резистор переменный убрать и посчитать здесь https://yahobby.ru/calc
MC34063 калькулятор

Номиналы деталей в схеме преобразователя:

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. Простая среда разработки и простые аппаратные средства – именно то, что нужно для простого и нетребовательного ни к скорости, ни к ресурсам проекта:).
“Железо” копеечное: клон платки ProMini с контроллером ATMega328 на борту и преобразователь USB-UART. А больше, пока, ничего не нужно:

невероятно сложно перейти на импульсные источники питания. Всегда же собирался транс выпрямитель 2 кондера и кренка ну 7805 или 7812 а то и без нее напрямую, так вроде надежнее. А перейти на какие то микроконтроллеры это совсем новое но придется, это же тоже цифра, логику 133 продали на золото а 155 закончилась. это еще и Плисы есть..fpga
Arduino ProMini и преобразователь 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 килоом к высокому напряжению подобрать – может побольше можно, снизит ток через лампы.

на схеме разряды биты d0 .. d7 условно
от программы зависит как и соединения. или наоборот, поправка в программе под готовую плату. на 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 общий –

Аналоги SN74141N, SN74141J Микросхема представляет собой высоковольтный дешифратор управления газоразрядными индикаторами.Предназначена для преобразования двоично-десятичного кода в десятичный. Дешифратор состоит из логических ТТЛ-схем и десяти высоковольтных транзисторов. На входы X1-X4 поступают числа от 0 до 9 в двоичном коде, при этом открывается соответствующий выходной транзистор. Номер выбранного выхода соответствует десятичному эквиваленту входного кода. Коды, эквивалентные числам от 10 до 15, дешифратором на выходе не отображаются. Содержит 83 интегральных элемента.

К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 они и в шестнадцатеричном так же.

Сразу не заметно – надо сначала сказать что у ИН-14 пятерка это развернутая двушка. а у ИН-8 московского завода уже обычная нормальная.

У лампы ИН-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.

Запуск декатрона от 12 вольт. Без умножителя. Детали – AIC1563 = MC34063, емкость задающая частоту примерно 300 пикофарад, не отпаивал, но работает на 95 килогерц. ** 430 pF измерял Еленой 7-8. КП813Б1 и примерно 20 витков на первичной обмотке, 190 на вторичной – до заполнения почти. Диод КД226Г 600 вольт 10 ампер импульс – до 50 даже и 1.7 – 2 ампера постоянно. У осциллографа вход 1.5 мегома 150 пикофарад – 570 вольт на вторичке показывает напрямую но надо крутануть отклонение луча – на 2-х экранах .. не совсем правильно так делать – лучше высоковольтный делитель из 2-х резисторов. Снаббер не надо – гармоник мало, кольцо 3 вольта желтое от компьютерного блока – металлопорошок альсифер в Китае оно Индуктор 15 ампер. Делитель 1.2 мегаома и 2к7, это соответствует 560-570 вольт. Ограничитель тока 220 миллиом запаян резистор он с серебристой полоской сверху маленькой платы. Ток потребляемый от 10 вольт пол ампера, на анод декатрона 1020 килоом, что то очень большой ток, подбирать надо катушку и частоту работы – наверно перебор раза в 2. Резистор задающий напряжение – чуть побольше можно и второй в делителе конечно. *это кольцо и есть основной трансформатор для конструкции 6ватт макс. hi-pot I=18 II=190 III=2 или 1 600 200отвод 4.5в пропаял все и ток 550 ма от 11 вольт со всеми включенными лампами и декатроном и всеми микросхемами от 5 вольт. Меньше 6 ватт на 7 ламп ардуинку и 6 6тук ИД1 – это неплохо, меньше чем по инструкциям до 2 ватт декатрон около 1 мА ИН1 то есть 1 ватт штука и 100мА дешифратор.** блок проверял на 15 18 ватт при прожиге ламп. Работает, нагрев до 40 градусов транзистора он на маленьком радиаторе 4 на 6 см с полосочками из алюминия 3 мм. В этой конструкции все зависит от этого источника, 3 напряжения с одной катушки и довольно точно. Когда настраивал обнаружил что в снятой плате с модема уже установлен делитель на 39к и второй резистор 390 скорее всего, и что 2 лапа микросхемы соединена в с выходной цепочкой а первая с 7-й то есть схема была та же. 2 раза ремонтировал менял регистры и еще одну ид1 но источник не при чем.
У такой лампы загораются точки по одной или несколько сразу. Надо повыше еще напряжение, на плате даже маловато написано. 450в 600 микроампер.

Вот этот эффект на декатроне показывает секунды. Он делается 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 как стиральная доска).

есть видео клип – проверка лампочек

https://youtu.be/yCQJiVp117E

Вот схема крутилки на декатроне – там в тексте развернутом написано какие выводы у декатрона соединять. Радиолюбитель возмет 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 есть крутилка на двух декатронах схема.

резисторы млт красненькие или С2-14 на мощность полватта а к анодам на 2 ватта лучше большие. аналоги транзисторов еще раз npn кт904а он на 300 вольт pnp кт502е 90 вольт можно чуть больше. Желтая точка на плоскости белая сверху. Выводы g1 g2 как видно в отключке.

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

обычный блок питания на трансформаторе вот все такие были до 80-х годов
маятник на декатроне – огонек бегает туда сюда
на G+ 100v RTN 50v A+ 570v circuit tested OK Russian A101 КТ940А КТ502Е (можно делать оно работает) но дерется! как вдарит зачем то.. да у меня не множик а сразу вч транс и выход на 600, через КД226К и на кондер 1000 в 1мкФ. В перчатках надо блин и провода от тестера поизолировать – чуть трещинка как врежет!
аналоги кт940а кт502е он на 90 вольт но вполне хватает, желтая точка на грани и белая сверху. на лампе напряжения 30- 40 может 90 вольт при g1 g2 около 100 вольт – это гашение разряда. Ардуинка если чего не погорит – стабилитрон ограничит 5в напряжение. Ставим аналоги хотя они по 120 руб. а импортные 12.. 70р 4 штуки на доллар но за морем телушка полушка да рубль перевоз. На немецкой схеме нарисован делитель высокого напряжения с кондерами – так и надо делать. примерные напряжения – g1 g2 если а101 около 90 -110 вольт rtn ndx в работе не больше 70 а то и 50 вольт. После r15 это 200к с коллектора кт502е или mpsa92 – ставится стабилитрон на 4.7 вольта на землю – для защиты ардуинки . При нормальной работе там 3.8 вольта .

Применяется А-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 он будет гореть.

питание от розетки 220 и 110 – часы от батареи так что будет схема выше на MC34063, а эта для предварительной настройки.

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

В частотомере используются первые 2 декатрона с синим разрядом – он не такой яркий но очень скоростной до миллиона в секунду – на водороде повидимому и гелии. А потом оранжевые – гелий неон. Те что у меня А101 работают до 1500 герц, не очень шустрые а вот разряд красивый краснее чам неонка. Разница есть и как между лампами с газовым разрядом – плазма рыжая это неон а более красная гелий в смеси и ртуть – зелено белый добавляется в высокой частоте если проверять катушкой Теслы.. Ртуть увеличивает время работы ламп как считается с 500 до 5000 часов , на самом деле могут работать несколько лет если не перегружать большим током – резистор в цепи анода у декатрона 750 килоом а у ламп – подобрать – еслми 165 вольт то 30 килоом, для ИН 14, если 305 вольт то 75 килоом или больше даже это для ИН 1.

еще где то видео где декатрон зажигает светодиоды и трубку Никси, только красиво если один огонек бегает. А самый красивый эффект даже не маятник а как в глазке от лампового усилителя VU-meter magic eye. Я такую штуку застал еще – в катушечном магнитофоне это был уровень записи, сейчас есть лампа советская и китайская они разные. Это зеленого свечения глазок и там чем больше звук тем больше засветка ! будет, часы могут быть совмещены с приемником или блютуз колонкой. Волюметер лучше по русски измеритель громкости, неправильно язык искажать – если русских слов нет они появятся. На декатроне еще красивее , чем больше сигнал тем больше штырьков катодов загораются – смотрим на плазму а это четвертое состояние вещества. (программа к ардуино чуть выше) .Еще один эффект – секунды – перемещается огонек по кругу и зажигает все штырьки за ним а потом так же гасит начиная с первого.

На плате лампа которая показывает минуты другая, с мелкой сеткой, она МЭЛЗ, остальные Брянские Анод, но разного времени выпуска , от 1970 до 1991. 6 штук ИД1 надо – по одному на лампу, 10 цифр, четвертый регистр будет управлять декатроном или двумя. Катушка намотана проводом с фторпластовой изоляцией, на ней установится напряжение 280 и 560 вольт после удвоителя. Выдержит и 560 вольт с обмотки, сердечник желтое кольцо металлопорошок, транзистор переключающий первичную обмотку КП813Б1. Металлобумажный кондер проверять удвоенным напряжением то есть 1200 вольт на нем написано 1500, это деталь от силовой техники, он 1963 года, это дорогая штука и совсем не безопасная, осторожно! Серая деталька не резистор а ограничитель напряжения на 560 вольт 1 ватт. Газовый стабилитрон от телека СГ301С на 400 вольт, немножко не подходит, хотя может и пригодится, добавить ему 20 вольт и он сделает ограничение 420 на декатрон – это как раз по его паспорту, чтобы разряд между электродами не загорался. В старой книжечке написано что для А101 максимальное напряжение 1000в и резистор 2 мегома. Нашел СГ302С и СГ303. ИН1 хочет по тех. описанию 200 минимум а лучше 230 вольт, на китайской плате под ИН14 напряжение меньше -примерно 165 вольт, для надежной работы со сборками uln2003. 230 в. питание а если убавить 60 вольт которые допустимы на выходах ИД1 то останется 170 вольт, что должно быть не достаточно для зажигания ламп, если будет засветка не тех цифр то придется снизить напряжение. В источнике питания от 12 вольт напрашивается отвод от катушки или трансформатор, на лампы надо 210 вольт а на декатрон 420, удвоитель, но это я подбираю КП813 чтобы был КПД преобразователя выше 90 процентов, может устроит 400 вольт и 200. Более сложный вариант – управление как у декатрона, требует 10 высоковольтных транзисторов на лампу. Статическая индикация – цифры записываются в регистры и не меняются до следущей записи.

Кондер если на 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 то есть отключение выхода, устанавливается за какие то нано секунды неопределенное состояние, не уверен но на отключенном выходе может напряжение разогнаться из -за наводки еще – если провода длинные.

https://yahobby.ru/wordpress/wp-content/uploads/2021/03/img_605a25e98bf6d.gif
https://www.arduino.cc/en/Tutorial/Foundations/ShiftOut

настройка блока питания – выходы 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 вольт питания.

https://t.me/radio1ru/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

Видео будет ночью. И в пещере..

катод не сильно отравлен. Резистор установлен 56к чтобы снизить потребление тока. Для прожига устанавливается 10к 2 ватта (к +200 вольт и на анод конечно) и оставляется при переборе всех цифр на минут 15. Меньше 10к нельзя а то не выдержит 155ИД1, от большого тока пользы не будет. Потом можно подобрать 47- 56 -33к – на крайний случай 18к если не горят хвостики у семерок- мощность 6 – 9 – 11 ватт у 6 ламп а срок работы 30- 15 -3 года. паспорт прибора – молибден катоды, никель и сплав Секретный ХМВ WolfRahm
https://www.facebook.com/permalink.php?story_fbid=2954545304830546&id=100008253161785&cft[0]=AZXv542MJknyQVkhcvZWP_EDUM9folnYSAxrMrY9RMGBNnJuMMqs6puVzdcADCVUwsg_0MG30vZQVn4wluxEnuR9UliuExBOjGef-wn3MX15vJKUNBmav7dDMnt9eKsqoAcWK5Zz2_L1egL2QYj549Kf&tn=%2CO%2CP-R

весь каталог 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 ма блок питания от Сеги, с ним и проверялось, будут работать в помещении без электрики где такие помещения смотрим другие записи на сайте.. )

индуктивность первички 22 ток по 200 вольтам 120 ма если прожигать катоды мощность 22 ватта импульсный ток больше 6 с половиной ампер что при допустимых 30 не на пределе. Сердечник только альсифер сендаст или китайский коллоидное железо а феррит не потянет по мощности кроме чашки ч 40 + При обрыве резистора измеряющего напряжение 600 вольт ничего не сгорает. Это самая ответственная деталь в конструкции. Кусочек платки с чипом mc34063 и пяток деталюшек не считая катушечки от компьютерного БП. Обмотки в тексте там 600 200 и 5 от 12 вольт и будет вариант 3 витка 5 витков 180 отвод и 600 пэтф или пэлшо соответственно на 3 вольта. Только сердечник побольше как раз чашка или 35 мм кольцо. На 3 вольта 2 управляющие микросхемы вторая делает из 3 вольт 12 для ключей. и 2 транзистора irfz44 запараллеленых – если номограмму перерисовать то получится 100 ампер при 20 ваттах импульс конечно.

проверил блок на 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-м со слов отца). Надеть перчатки и настраивать в сухом помещении тогда опасности нет. Высоковольтную часть после настройки можно залить термоклеем – прозрачным который палочки для пистолета.

еще короткий повтор (__ )

Это изображение имеет пустой атрибут alt; его имя файла - Снимок-экрана-от-2020-10-02-10-25-41.png
дешифратор – входы не инверсный адрес – ошиблись просто а выходы да – активная цифра включается нулем
Это изображение имеет пустой атрибут alt; его имя файла - 29.gif
регистры
Это изображение имеет пустой атрибут alt; его имя файла - F1UWUMUI8PQUCUU.png
схема секундных – 14 с 9 лапы регистра минут а на минутах идет 9 вывод с часов на 14 а на часах на 14 приходит Digital11 с ардуино .Лампы конечно ИН1.
Газоразрядные индикаторы ИН1 — ИН14 | Электрические схемы
Radiotech modding labs: Знаковые газоразрядные индикаторы

линейка светодиодов. сделана году в 1989 для отладки мк 8051 и даже материнских плат ПК. Так же сделана плата регистров – они очень хрупкие и чувствительные даже к помехам по питанию – емкость керамика на плате и рядом 2000 мкф 16 вольт электролит. Плата делается за 15 минут резаком из полотна ножовки либо старого ножика,заточка как маленький крючок. Раньше так часто ставились планарные чипы, недавно сделан адаптер для программатора микросхем в корпусе tsop – дорожки нарезаны на 3 – 4 сантиметра а микросхемка отпаивается феном. Для игровой приставки но можно прошивать например bios от материнки либо другие устройства модем модули памяти видеокамеры – короче хакерская штука такая.

нашел сборку резисторов 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 у маленькой ардуинки

https://yahobby.ru/wordpress/wp-content/uploads/2021/05/obzor-chasov-realnogo-vremeni-ds3231-3.jpg

как видно на фото подтягивающие резисторы 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В), схема собрана, теперь надо подготовить программную часть.

резистор 200 ом для зарядки 3 элементов никель-кадмиего аккумулятора – кто их застал в синей трубочке такие 3 таблетки и стояли на платах ibm pc 1986 .. если литиевая батарейка отпаять его вместе с диодиком 1n4148 иначе запрограммирован взрыв и пожар. Литиевые больше чем 4.2 нельзя заряжать, и незачем – новая батарейка CR2032 поработает 5-10 лет. 8 по 5к6 удобнее для самоделки не планар а с выводами или резисторы просто маленькие. На модуле все есть – вот они снизу черненькие штучки.
Обзор часов реального времени DS3231 (RTC)

Библиотеки работающий с 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 и открываем «Мониторинг порта»

Обзор часов реального времени DS3231 (RTC)

#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% _*? ” (материмся патрон нет)
надо открыть вольер с караульной собакой ес _ (кончилась память)
(ошибка сенсора) .. Извиняюс.т

Обзор часов реального времени DS3231 (RTC)

Ссылки
  Библиотека libraries-DS3231

https://github.com/jarzebski/Arduino-DS3231

https://t.me/radio1ru/14

https://t.me/radio1ru/15

https://t.me/radio1ru/12

ставим 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 5 
connect buttons
to 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 с резисторами на аналоговый вход зато на один. Что то передается на другую ардуинку с декатроном – режим или быстро-мндленно. датчик освещения может прикручу. Индикация в статике – и светит конкретным оранжевым огнем, что то может с регулировкой света ночью – только не отключать. И так добивает этот свет в подьезде – чтобы его включить нало щелкнуть языком а то и гавкнуть. А часы должны показывать время, ворочаться шевелиться и щелкать ночью неохота. Ниже чуть алгоритм.

untitled

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;
}

 

сброс у микросхемы часов через 100к к питанию.

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

About the lynx | Russian Geographical Society

сделал кнопку работает но на ощупь. Придумываю как сделать эффект затемнения 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;
  }
} 

 

300 кгц последовательные данные 600и 930 почти мегагерц синхронизация (как просто увидеть глазами здесь написано)

Авторское обновление программы – в основном добавлены адресные светодиоды на них бум. И еще инфракрасный датчик движения – включается при приближении. В динамике как я перевел на этот режим – более экономичное изделие. Я сравниваю с китайской платой так у этих 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://yahobby.ru/nixie-clock-часы-на-цифровых-лампах

образец для этих часов – 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»). Затем часы перейдут в нормальный режим работы.

Процесс запуска смотрите здесь:

https://youtu.be/XA3LOPLX8vI

Как только вы выйдете из режима запуска, то при последующих включениях он не будет вновь запускаться пока вы не выполните сброс настроек (см. ниже).

Режим часов

После первого запуска каждый раз, когда вы включаете часы они переходят в обычный режим часов и отображают время. Каждые 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 -сегментных индикаторов.

Для ив-22 допустимо последовательно соединить накал у 4 ламп и включить от 5 вольт. А можно и на дроссель у 34063 намотать 1 -2 -3 витка и с них взять напряжение, надо 1.3 вольта. По другой схеме с часового кварца 32 кгц идет сигнал так же усиленный 2 транзисторами кт3102 и кт3107 , и на вч трансформатор там надо 16 витков первичная и 2 витка вторичная – на накал ламп 1.27 вольта, мощность около полватта на 4 лампы дяже на 6.

 

ссылки Метеостанция предсказатель погоды project Modular Weather Station .

волюметер vu-meter с использованием ИН-13 .. покупал парочку на Толкучке у магазина радио на Шаболовке то ли у магазина у Маяковской она потом переместилась ближе к нам на Покровско-Стрешнево, Тушинский рынок и потом в Митино. Это был 1988 год примерно, не наверно 1986 уже были микро 80 и радио 86 рк но до Синклера и Z80

vu-meter на декатроне.

Эффект на полиатроне А201.

Магический глаз magic eye . 2 варианта зеленого огонька от магнитофона или приемника, на китайской лампе и советской.

Часы на одном декатроне А101 . Светящиеся точки соответствуют 3 стрелкам часов, можно сделать и на других ОГ4 например но сложнее.

обжигалка и летящие провода медный с обмотки пэв 2

http://t.me/radio1rus

http://discord.gg/vFKWfKm8

 

Силовая техника – запуск дизеля 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 штуки логики, его работа была расшифрована на маленьком стенде подавая разные импульсы и смотря что на выходе. из приборов линейка светодиодов и все.)

https://yahobby.ru/nixie-clock-%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%d1%85-%d0%bb%d0%b0%d0%bc%d0%bf%d0%b0%d1%85

 Пошарашил за лампами. Рыська скинула с полочки – все часы хоть бы что, а вот одна лампочка ИН -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

Download Attachments

5 Replies to “Часы на цифровых лампах”

  1. комментарий к источнику высокого напряжения – если он на Мотороле 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 вольт рассчитана

  2. Опять по источнику. подглядел на известном форуме, сейчас конечно программы и компы меньше сложностей вызывают.. чем 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 ватта. Если будет форма сигнала без резкого выброса – пила называется, резистор измеряет ток через дроссель, то все правильно, если ток резко возрастает в виде короткого всплеска – дроссель насыщается и не подходит.

  3. програмки есть во вложенияхъ
    пока текст статьи часто редактируется – может быть испорченый код , особенно символы >> < ^%&

  4. на первой картинке. Декатрон установлен в часах, он дает просто эффект для красоты – пружинка Слинки. Этот прибор как неоновая лампа, только счетчик импульсов и показывает сразу сколько их было. Работал в связке со счетчиком Гейгера, если огонек быстро перемещается по кругу и проходит 5 импульсов за секунду – загорается неонка Внимание Радиация! Если огонек несется по кругу то срочно в укрытие, чем быстрее тем лучше. а вот здесь мирное применение.

    без всяких обсуждений, сейчас скорее всего пригодится. Подвал ослабляет радиацию в 10 раз, метро или бункер в 1000 раз. У кого нет дозиметра помрет от непонятно чего так что есть смысл срочно купить.

Leave a Reply

Your email address will not be published. Required fields are marked *