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

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 KiB, 3 859 загрузок)


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

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

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

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

Корпус без покраски. Вид снизу.

Корпус без покраски. Вид сверху.

Подгон верхнего отверстия. Все делал на глаз.

Плата закреплена внутри корпуса с помощью обычного клеевого пистолета

Насверлил кучу отверстий для охлаждения

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


IMAG0007

Запись опубликована в рубрике Arduino. Добавьте в закладки постоянную ссылку.

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

  1. Artur говорит:

    10000 pублей eжeднeвно, безвозмезднo, навсeгдa. Тyт-жe на Вашу банkовскую карту или элeктронный koшелek. Ho это при уcлoвии, чтo Вы пpоживaете нa территории Pосcии, либo cтранaх CHГ; C Baми должнa бытb oбратнaя cвязь: почтa , либо телeфон. Bce очeнь пpостo. Mы эkономим на нaлогaх, а вы полyчaете пoлноe oбеcпечeниe нa долгиe годы. И глaвноe — oт вас coвepшеннo ничегo нe нужнo взaмeн. Этo Вaша дocтойная зapплaта.

Добавить комментарий

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