Ретро-часы Nixie Clock: как сделать
В этой статье мы разберемся как сделать модные олдскульные часы Nixie Clock и при этом обойтись без дефицитных газоразрядных ламп. Вместо них используем акриловые пластины с выгравированными цифрами, которые подсветим адресными светодиодами WS2812B.
Видеообзор
Что это?
Каждая цифра это вырезанный лазерным резаком из прозрачного акрила толщиной 3 мм прямоугольник на котором сделана гравировка. Если посветить в торец такого прямоугольника светодиодом, то выгравированная цифра начнет светиться цветом, которым светит светодиод. Собрав 10 таких цифр в блок и подсвечивая каждую пластинку акрила отдельным светодиодом можно по-отдельности зажигать каждую цифру. В качестве светодиодов будем использовать адресные светодиоды WS2812B. Управляются они занимая один контакт управляющей платы, при этом их можно объединить в цепочку и задавать яркость и цвет свечения каждому из них. Блоки цифр объединим по парам для отображения часов и минут. Управлять светодиодами будет Искра Мини с тройка модулем часов реального времени.
Что понадобится?
- Адресные светодиоды WS2812B ( 41 штука, но лучше взять с запасом )
- Прозрачный акрил. Фактическая толщина 2, 93.
- Чёрный непрозрачный акрил 3 мм.
Воспользоваться лазерной резкой можно в любом агенстве наружной рекламы. Но гораздо интереснее поработать на лазере самостоятельно. Например в ФАБ ЛАБ.
Как собрать?
А вот и архив CorelDRAW векторных файлов для резки. Обрати внимание, что я исходил из конкретной толщины прозрачного аркила (2,93 мм) и допусков, которые варьируются от материала к материалу и модели лазера.
- Каждая цифра будущих часов это отдельная пластинка из прозрачного акрила, с двумя ножками для крепления и световодом в который будет светить светодиод.
- Чтобы светодиоды не засвечивали соседние пластинки в блоке цифр, сделаем панель из чёрного, непрозрачного акрила с отверстиями ограничивающими световой поток.
- Вставим пластинки с цифрами в светоограничивающую панель. Туда же отправим разделительные точки для индикации хода часов.
Снизу в панели будут видны торчащие световоды каждой из цифр.
Длина этих световодов такая чтобы светодиод прилегал к ним вплотную.
- Сделаем площадку для адресных светодиодов так, чтобы каждый из них светил точно в световод пластинки с цифрой и оденем её на торчащие световоды.
- Обрати внимание, что у светодиодов есть один срезанный угол. Он нужен чтобы сориентировать тебя, где какой контакт.
Распиновка светодиода WS2812B
- Самое время установить светодиоды в свои места. Отогнем контактные ножки светодиодов, чтобы к ним было удобнее подпаяться и вставим их в посадочные места.
- Для точной работы часов к Iskra mini добавим модуль часов реального времени. Это удобно сделать если использовать Troyka Mini IO.
- Подключим кнопку и потенциометр
- Теперь питание и линии DI светодиодов
Исходный код
Прошей Iskra Mini кодом программы.
- ledClock.ino
// библиотека для работы с адресными светодиодами #include <Adafruit_NeoPixel.h> // библиотека для работы I²C #include <Wire.h> // библиотека для работы с часами реального времени #include "TroykaRTC.h" // библиотека для работы с кнопками #include "TroykaButton.h" // инициализируем подключенную кнопку TroykaButton button(10); // номер пина, к которому подключена RGB-матрица #define MATRIX_PIN 11 // количество светодиодов в матрице #define LED_COUNT 40 // инициализация цепочки светодиодов подсветки цифр Adafruit_NeoPixel matrix = Adafruit_NeoPixel(LED_COUNT, MATRIX_PIN, NEO_GRB + NEO_KHZ800); // инициализация светодиода разграничителя Adafruit_NeoPixel dot = Adafruit_NeoPixel(1, 12, NEO_GRB + NEO_KHZ800); // размер массива для времени #define LEN_TIME 12 // размер массива для даты #define LEN_DATE 12 // размер массива для дня недели #define LEN_DOW 12 // создаём объект для работы с часами реального времени RTC clock; // переменные для мигания int ledState = 0; unsigned long previousMillis = 0; unsigned long currentMillis ; // массив для хранения текущего времени char time[LEN_TIME]; // массив для хранения текущей даты char date[LEN_DATE]; // массив для хранения текущего дня недели char weekDay[LEN_DOW]; int hour; int minute; int one; int two; int three; int four; int displaysettings=0; int red=150; int green=200; int blue= 50; void setup() { // инициализация button.begin(); matrix.begin(); dot.begin(); clock.begin(); // метод установки времени и даты в модуль вручную // clock.set(hour,minute,0,27,07,2005,THURSDAY); // метод установки времени и даты автоматически при компиляции clock.set(__TIMESTAMP__); // что бы время не менялось при прошивки или сбросе питания // закоментируйте оба метода clock.set(); pinMode(10, INPUT_PULLUP); } void loop() { // считываем состояние кнопки button.read(); // запрашиваем данные с часов clock.read(); // считаем нажатия чтоб переходить из режима в режим if (button.justPressed()){ displaysettings = displaysettings + 1; } if(displaysettings==0){ // сохраняем текущее время hour = clock.getHour(); minute = clock.getMinute(); } if(displaysettings == 1){ // присваиваем значение считываемое с потенциометра hour = map (analogRead(A0),2, 1020, 0, 23); clock.set(hour,minute,0,27,07,2005,THURSDAY); } if(displaysettings == 2){ // присваиваем значение считываемое с потенциометра minute = map (analogRead(A0), 2, 1018, 0, 59); clock.set(hour,minute,0,27,07,2005,THURSDAY); } if(displaysettings == 3){ // присваиваем значение считываемое с потенциометра red = map (analogRead(A0),0, 1023, 0, 255); } if(displaysettings == 4){ // присваиваем значение считываемое с потенциометра green = map (analogRead(A0),0, 1023, 0, 255); } if(displaysettings == 5){ // присваиваем значение считываемое с потенциометра blue = map (analogRead(A0),0, 1023, 0, 255); } if(displaysettings == 6){ displaysettings = 0; } // делим минуты и часы на разряды one = hour / 10; two = hour % 10; three = minute / 10; four = minute % 10; matrix.clear(); // зажигаем нужные светодиоды matrix.setPixelColor(four, red, green, blue); matrix.setPixelColor(three + 10, red, green, blue); matrix.setPixelColor(two + 20, red, green, blue); matrix.setPixelColor(one + 30, red, green, blue); matrix.show(); // ждём одну секунду delay(10); // мигание разделителя blinking(); } void blinking(){ if (millis() - previousMillis >= 1000) { previousMillis = millis(); if (ledState == 0) { ledState = 1; dot.setPixelColor(0, red, green, blue); } else { ledState = 0; dot.setPixelColor(0, 0, 0, 0); } dot.show(); } }