Nixie Clock (часы на газоразрядных индикаторах)

Года 2 назад, я узнал о замечательных советских газоразрядных индикаторах. До этого,  я конечно видел, что то подобное в старой советской технике, но никогда не задумывался, что такие индикаторы можно применить в быту, довольно таки в многочисленных проектах, в которых нужно выделить эдакую эстетическую изюминку. Свою популярность эти индикаторы вновь приобрели среди радиолюбителей несколько лет назад из за своего антикварного вида и довольно красивого визуального отображения индикации. В интернете уже сейчас можно найти прекрасные реализации часов на советских ИНках, но мне с самого начало хотелось  разобраться с принципами построения таких часов, написать свою прошивку и сделать самодельный корпус из подручных материалов. Не давно я выкроил время и соорудил свои собственные часики на платформе arduino. Самым сложным оказалось достать эти индикаторы. В моем городе я так их и не нашел. Через форум сайта радиокот,  нашел человека, который как раз был не далеко в г. Омске. Купил у него 6 ламп ИН-14 и 12 ламп ИН-12Б, а также 6 высоковольтных дешифратора К155ИД1.

Набросал вот такую схему, которую подглядел на каком то сайте. Здесь мы видим 2 высоковольтных дешефратора К155ИД1, 6 трубок ИН-14, преобразователь напряжения с 12 до 180В для питания анодов колб. Подсветку сделал с возможностью управлять через микроконтроллер, но ума так и не дал. Просто постоянно горит. Пищалку позднее я вообще подключил мимо транзистора напрямую к модулю с атмегой. Почти все компоненты используются в планарном исполнении.

Nixie_clock_shematic

Модуль с атмегой и часами реального времени ds1307 сделал на отдельной плате. Я использовал atmega168PA-AU, но в данном проекте можно смело использовать atmega8PA или atmega88PA (просто зашейте соответствующий bootloader), работающие от внутреннего осцилятора 8MHz.

Nixie_clock_atmega
Схема модуля atmega + ds1307
Nixie_clock_atmega_board
Печатная плата модуля atmega + ds1307

Далее написал вот такую простенькую прошивку с помощью Arduino IDE 1.0.3. Как видим в начале скетча идет определение пинов К155ИД1, анодов и другой периферии  Так, что кто захочет извратится и сделать такую схему на макетке с обычной ардуиной можете переназначить на другие удобные вам порты. Есть 2 режима отображения: время и дата, настройка часов, 1 анимация.  Я немного пытался оптимизировать исходный код, некоторым новичкам может потребоваться время на его осмысление. Советую почитать вот это для начала.

#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 RTC;

// К155ИД1 (1)
uint8_t Pin_1_a = 14;
uint8_t Pin_1_b = 16;
uint8_t Pin_1_c = 17;
uint8_t Pin_1_d = 15;
// К155ИД1 (2)
uint8_t Pin_2_a = 5;
uint8_t Pin_2_b = 7;
uint8_t Pin_2_c = 8;
uint8_t Pin_2_d = 6;
// Анодные пины
uint8_t Pin_a_1 = 11;//колбы 1, 4
uint8_t Pin_a_2 = 10;//колбы 2, 5
uint8_t Pin_a_3 = 9; //колбы 3, 6

#define DOT_ON PORTB|=1<<PINB4 // Точки Вкл
#define DOT_OFF PORTB&=~(1<<PINB4) //Точки Выкл

#define LIGHT_ON PORTD|=1<<PIND4 // Подсветка Вкл
#define LIGHT_OFF PORTD&=~(1<<PIND4) //Подсветка Выкл

#define SPEAKER_ON PORTB|=1<<PINB5 // Пищалка Вкл
#define SPEAKER_OFF PORTB&=~(1<<PINB5) //Пищалка Выкл
//Подтверждение настроек
#define TIME_UP (PIND & (1<<PIND3))//Считывание значения кнопки на порту 3
//Перебор настроек
#define TIME_SET (PIND & (1<<PIND2))//Считывание значение кнопки на порту 2

static const uint8_t bits[2][4] =
{
{Pin_1_d, Pin_1_c, Pin_1_b, Pin_1_a},// К155ИД1 (1)
{Pin_2_d, Pin_2_c, Pin_2_b, Pin_2_a }// К155ИД1 (2)
};

uint8_t mode = 0;

//Массив для управления анодами ламп
static const uint8_t anods[3] = {Pin_a_1, Pin_a_2, Pin_a_3};

//Массив с помощью которого дешефратору задаются цифры
static const uint8_t numbers[11][4] =
{
{ 0, 0, 0, 1 }, //0
{ 0, 0, 0, 0 }, //1
{ 1, 0, 0, 1 }, //2
{ 1, 0, 0, 0 }, //3
{ 0, 1, 1, 1 }, //4
{ 0, 1, 1, 0 }, //5
{ 0, 1, 0, 1 }, //6
{ 0, 1, 0, 0 }, //7
{ 0, 0, 1, 1 }, //8
{ 0, 0, 1, 0 }, //9
{ 1, 1, 0, 1 } //Чисто
};

// Массив для анимации, перебор всех цифр в колбе
static const uint8_t nixie_level[10] = {
1, 2, 6, 7, 5, 0, 4, 9, 8, 3
};
//Массив для 6 колб
int NumberArray[6]={0,0,0,0,0,0};

uint8_t Mins = 0;
uint8_t Seconds = 0;
uint8_t j=0, z=0;
uint8_t timeset = 0;
boolean ok =false;
boolean up =false;
boolean animate =false;
boolean sec=true;

void setup()
{
Wire.begin();//Инициализация шины I2C
RTC.begin();//Инициализация микросхемы часиков ds1307
DDRD = B11110010; // назначаем выводы 1,4,5,6,7 как выходы, вывод 0,2,3 - входы
DDRB = DDRB | B00111111; // назначаем выводы 8,9,10,11,12,13 как выходы
DDRC = DDRC | B00001111; // назначаем выводы 14,15,16,17 как выходы
PORTD = B00001100; //Подтягивающие резисторы для кнопок на портах 2, 3.
LIGHT_ON;// Включаем подсветку ламп. Ума не дал этой функции :)
}

static void setNixieNum(uint8_t tube, uint8_t num) {

for(uint8_t i=0; i<4; i++)
{
digitalWrite(bits[tube][i], LOW);//боримся против глюков - обнуляем
if (!animate) digitalWrite(bits[tube][i], numbers[num][i]);
if (animate) digitalWrite(bits[tube][i], numbers[nixie_level[j]][i]);
}

}

void DisplayNumberSet(uint8_t anod, uint8_t num1, uint8_t num2 ) {
setNixieNum(0, num1);
setNixieNum(1, num2);
digitalWrite(anods[anod], HIGH);
delay(3);
digitalWrite(anods[anod], LOW);
}

void loop() {
///Счетчик для анимации///
if (z==8)
{
j++;
z=0;
}
if (j==10) {animate=false; j=0; z=0;}
if (animate) z++;
///////////////////
DateTime now = RTC.now();
Seconds = now.second();
Mins=now.minute();
//Режимы часов Время, дата
switch(mode)
{
case 0:
NumberArray[0] = now.hour() / 10; //Первый знак часа
NumberArray[1] = now.hour() % 10; //Второй знак часа
NumberArray[2] = Mins / 10; //Первый знак минут
NumberArray[3] = Mins % 10; //Второй знак минут
NumberArray[4] = Seconds / 10; //Первый знак секунд
NumberArray[5] = Seconds % 10; //Второй знак секунд
//Вырубаем точки
if (timeset==0)
{
DOT_OFF;
}
break;
case 1:
NumberArray[0] = now.day() / 10; //Первый знак дня
NumberArray[1] = now.day() % 10; //Второй знак дня
NumberArray[2] = now.month() / 10; //Первый знак месяца
NumberArray[3] = now.month() % 10; //Второй знак месяца
NumberArray[4] = (now.year() / 10) % 10;//Первый знак года
NumberArray[5] = now.year() % 10; //Второй знак года
//Если не в настройках то мигаем всеми точками
if (timeset==0)
{
//Если знак секунды четный то включаем иначе выкл
if ((Seconds % 10)%2==0)
{
DOT_ON;
}
else
{
DOT_OFF;
}
}
break;
}

if (timeset==0){
//Каждые пол часа пищим
if ((Mins == 0)&&sec||(Mins == 30)&&sec)
{
playTone(200, 2500);
sec=false;
}
if ((Mins == 1)&&!sec||(Mins == 31)&&!sec)
{
sec=true;
}
//Каждые 55 секунд включаем время
if (Seconds==55)
{
mode=0;
animate=true;
}
//Включаем дату на 48 секунду
if (Seconds==48)
{
mode=1;
animate=true;
}
//Переключаем режимы
if (!TIME_UP&&!up)
{
up=true;
animate=true;
playTone(80, 2800);
mode++;
mode %= 2;
}
if (TIME_UP&&up)
{
up=false;
}
}
/**********Установка времени**********************/
//Перебор настоек
if (!TIME_SET&&!ok) {
ok=true;
timeset++;
if (timeset>=7)
{
timeset=0;
mode=0;
}
playTone(80, 2800);
}
if (TIME_SET&&ok) {
ok=false;
}

switch (timeset)
{
//Установка часов
case 1:
DOT_ON;
mode=0;
NumberArray[2] = 10;
NumberArray[3] = 10;
NumberArray[4] = 10;
NumberArray[5] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + 3600); // + 1 Час
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
//Установка минут
case 2:
NumberArray[0] = 10;
NumberArray[1] = 10;
NumberArray[4] = 10;
NumberArray[5] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + 60); // + 1 минута
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
//Установка секунд
case 3:
NumberArray[0] = 10;
NumberArray[1] = 10;
NumberArray[2] = 10;
NumberArray[3] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + 1); //+ 1 секунда
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
//Установка дня
case 4:
mode=1;
NumberArray[2] = 10;
NumberArray[3] = 10;
NumberArray[4] = 10;
NumberArray[5] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + 86400L); //+ 1 день
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
// Установка месяца
case 5:
mode=1;
NumberArray[0] = 10;
NumberArray[1] = 10;
NumberArray[4] = 10;
NumberArray[5] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + (86400L*31)); //+ 1 месяц
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
//Установка года
case 6:
mode=1;
NumberArray[0] = 10;
NumberArray[1] = 10;
NumberArray[2] = 10;
NumberArray[3] = 10;
if (!TIME_UP&&!up)
{
up=true;
DateTime adjust (now.unixtime() + (86400L*365)); //+ 1 год
RTC.adjust(adjust);
playTone(80, 2800);
}
if (TIME_UP&&up) up=false;
break;
}
// Вывод данных на ИН-14.
DisplayNumberString( NumberArray );
}
//Функция "пищалки"
void playTone(long duration, int freq) {
duration *= 1000;
int period = (1.0 / freq) * 1000000;
long elapsed_time = 0;
while (elapsed_time < duration) {
SPEAKER_ON;
delayMicroseconds(period / 2);
SPEAKER_OFF;
delayMicroseconds(period / 2);
elapsed_time += (period);
}
}
void DisplayNumberString( int* array ) {

DisplayNumberSet(0,array[0],array[3]);

DisplayNumberSet(1,array[1],array[4]);

DisplayNumberSet(2,array[2],array[5]);
}
Прошивка и схемы

  Nixie_clock.zip (165,1 КиБ, 5 036 загрузок)


Полностью собранные часы. Платы спаяны землями.

Ну и последняя часть часиков это конечно внешний вид — корпус. Я его сделал из остатка сосновой плахи пятерки. В принципе никаких специальных навыков я не имею. Бывало на школьных уроках труда делал указки и на токарном станке скалку точил, но это было уже больше 12 лет назад. Просто нужно терпением запастись и несколькими инструментами. Итак понадобятся: лобзик или ножовка, стамеска, напильник, мелкая шкурка,  морилка на алкидной основе дубового или другого цвета, деревяха подходящего размера. Подробный фото отчет изготовления корпуса я не запечатлел,  так как изготавливал его на одном дыхании. Вкратце на словах несколько этапов:

1) Ножовкой или лобзиком облагораживаем наш без форменный кусок дерева до состояния прямоугольника близкого к идеальному :).
2) Cтамеской снизу выдалбливаем прямоугольник меньшего размера.
3) Cверху где лампы будут торчать, выдалбливаем, выпиливаем длинный и узкий овал по размеру ламп.
4) Шкурим, придаем углам овальности.
5) Делаем 6 отверстий для дна из простой деревоплиты или фанеры тонкой.
6) Покрываем корпус морилкой на 2 раза.

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

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

Как обычно в заключении выкладываю видео работы готовых часиков.


IMAG0007

комментариев 58

  1. Honestly, I’ve been browsing this cool forum for a long time, and I finally felt like to post a few things. For starters, from my experience most gamblers frequently ignore about proper budget control, and this completely defines your betting results. Plus, games lately look extremely unpredictable, and thus you absolutely ought to be mindful. Anyway, I ran into an helpful guide [url=https://telegra.ph/Leloquence-numerique-revele-wi-07-08]https://telegra.ph/Leloquence-numerique-revele-wi-07-08[/url], as it provides some cool strategies for increase the fun. I must add, I feel that running after losses is the easiest route to go broke, which is why you should learn when to call it a day. What are your views about that? Share your experience in the comments!

  2. Hi, friends, I’ve been checking out this awesome forum recently, and I felt like to share a few things. As a side note, from my experience a lot of gamblers often overlook about strict budget control, and this totally changes the betting success. Also, platforms right now look incredibly risky, so you absolutely must to watch out. Moving on, you should check [url=https://tiktok.com/@epicbet_bonus]epicbet login[/url], as it offers very decent insights on ways to increase your odds. It’s also obvious that running after bad runs is the easiest way to go broke, which is why you should know when to call it a day. How do you normally deal with a losing streak? Let’s hear your thoughts below!

  3. Beyler dinleyin Canlı destek yok, oranlar düşük, her şey çok kötüydü Ama sonunda bu siteyi keşfettim — 1xbet yeni giriş kolay Her gün özel bonus ve promolar mevcut Kısacası, kendiniz bakın — 1 xbet giriş [url=https://1xbet-giris-bwf.com]1 xbet giriş[/url] Tek adres 1xbet giriş Bahis yapan herkese yolla

  4. Ребята кто в теме Вечно то лаги Нервов потратил — мама не горюй Короче, нашел наконец толковое казино — vavada официальный сайт Фриспины и акции каждый день В общем, там все подробности — вавада казино онлайн [url=https://polezno-vsem.ru]вавада казино онлайн[/url] Не ведитесь на лохотроны Перешлите тому кто тоже ищет нормальное казино

  5. Just my two cents, I’ve been checking out this cool community recently, and I needed to post a few points. First off, I have seen that most gamblers usually overlook how crucial it is to have strict budget control, and this totally defines the overall results. Plus, casinos these days look much more dynamic, so you definitely must to watch out. By the way, I stumbled upon an excellent site [url=https://telegra.ph/Uleglosc-i-fascynacja-w-swieci-07-08]https://telegra.ph/Uleglosc-i-fascynacja-w-swieci-07-08[/url], as it shares some great insights for increase your chances. Moreover, I feel that trying to recover money lost is the easiest path to lose everything, which is why you should remember when to stop. What do you think about that? Share your feedback in the comments!

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.