Очень хороший вариант часов, если нужно только время (без датчиков) и есть постоянный интернет по wi-fi, понадобится только ESP8266-01, полтора метра адресной СДЛ WS2812B, блок питания или зарядка на 5в 1а, ну и стабилизатор, например, 1117 на 3,3в для питания модуля. Прошиваем ESP8266 любым конвертером USB-TTL, можно и ардуинку в этом качестве использовать, следующим скетчем:
#include <ESP8266WiFi.h> //Используемые библиотеки, должны быть установлены в среде Arduino IDE, или чем вы там собрались компилировать
#include <WiFiUdp.h>
#include <Adafruit_NeoPixel.h>
char ssid[] = "ZAHUYAKER"; //точку доступа и пароль к wi-fi ставим, конечно, свои
char pass[] = "romanchik_irinchik";
int hours =0;
int mins =0;
#define PIN 2 //GPIO2 модуля ESP8266-01
#define NUMPIXELS 86 //Общее количество адресных ссветодиодов WS2812B
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
unsigned int localPort = 2390;
IPAddress timeServerIP;
const char* ntpServerName = "time.nist.gov"; //сервер точного времени также не обязательно выбирать именно этот
const int NTP_PACKET_SIZE = 48;
byte packetBuffer[ NTP_PACKET_SIZE];
WiFiUDP udp;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("Starting UDP");
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());
pixels.begin();
}
void loop()
{
WiFi.hostByName(ntpServerName, timeServerIP);
sendNTPpacket(timeServerIP);
delay(1000);
int cb = udp.parsePacket();
if (!cb) {
//Serial.println("no packet yet");
}
else {
//Serial.print("packet received, length=");
//Serial.println(cb);
udp.read(packetBuffer, NTP_PACKET_SIZE);
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
const unsigned long seventyYears = 2208988800UL;
unsigned long epoch = secsSince1900 - seventyYears;
epoch = epoch + 3 * 3600; // 3 - коррекция часового пояса, ставим свою
hours = (epoch % 86400L) / 3600;
if (hours<24)
{
hours++;
}
if (hours==24)
{
hours=0;
}
mins = (epoch % 3600) / 60;
Serial.print(hours);
Serial.print(':');
Serial.println(mins);
drawdigit(0,155,0,0,hours/10);//Draw the first digit of the hour //0-20 номера светодиодов первой цифры, 21-41 втораой цифры, в каждом сегменте по 3сд
drawdigit(21,155,0,0,hours-((hours/10)*10));//Draw the second digit of the hour //42-43 точки между второй и третьей цифрами
pixels.setPixelColor(42, pixels.Color(155,0,0));//Draw the two middle dots //44-64 третья цифра, 65-85 четвертая цифра
pixels.setPixelColor(43, pixels.Color(155,0,0));
drawdigit(44,155,0,0,mins/10);//Draw the first digit of the minute //яркость выбрал 155, цвет - красный, при таком режиме потребление не более 0,9а, т.к. для питания часов
drawdigit(65,155,0,0,mins-((mins/10)*10));//Draw the second digit of the minute //использовался слабенький адаптер 5в 0,9а
delay(59500);//Request to NIST server should be separated by 60 seconds. //Можно реализовать и автосмену цвета и задать значения цветов, мне это показалось лишним
}
}
void drawdigit(int offset, int r, int g, int b, int n)
{
if (n==2 || n==3 || n== 4 || n==5 || n==6 || n==8 || n==9 )//СРЕДНИЙ СЕГМЕНТ
{
pixels.setPixelColor(0+offset, pixels.Color(r,g,b)); // 0, 1, 2 - последовательность подключения светодиодов, если у вас другая - ставим свои значения для каждого сегмента
pixels.setPixelColor(1+offset, pixels.Color(r,g,b)); //последовательность подключения в каждой цифре должна быть одинаковой)))
pixels.setPixelColor(2+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(0+offset, pixels.Color(0,0,0));
pixels.setPixelColor(1+offset, pixels.Color(0,0,0));
pixels.setPixelColor(2+offset, pixels.Color(0,0,0));
}
if (n==0 || n==1 || n== 2 || n==3 || n==4 || n==7 || n==8 || n==9)//ВЕРХНИЙ ПРАВЫЙ СЕГМЕНТ
{
pixels.setPixelColor(18+offset, pixels.Color(r,g,b));
pixels.setPixelColor(19+offset, pixels.Color(r,g,b));
pixels.setPixelColor(20+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(18+offset, pixels.Color(0,0,0));
pixels.setPixelColor(19+offset, pixels.Color(0,0,0));
pixels.setPixelColor(20+offset, pixels.Color(0,0,0));
}
if (n==0 || n==2 || n== 3 || n==5 || n==6 || n==7 || n==8 || n==9)//ВЕРХНИЙ СЕГМЕНТ
{
pixels.setPixelColor(15+offset, pixels.Color(r,g,b));
pixels.setPixelColor(16+offset, pixels.Color(r,g,b));
pixels.setPixelColor(17+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(15+offset, pixels.Color(0,0,0));
pixels.setPixelColor(16+offset, pixels.Color(0,0,0));
pixels.setPixelColor(17+offset, pixels.Color(0,0,0));
}
if (n==0 || n==4 || n==5 || n== 6 || n==8 || n==9 )//ВЕРХНИЙ ЛЕВЫЙ СЕГМЕНТ
{
pixels.setPixelColor(12+offset, pixels.Color(r,g,b));
pixels.setPixelColor(13+offset, pixels.Color(r,g,b));
pixels.setPixelColor(14+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(12+offset, pixels.Color(0,0,0));
pixels.setPixelColor(13+offset, pixels.Color(0,0,0));
pixels.setPixelColor(14+offset, pixels.Color(0,0,0));
}
if (n==0 || n==2 || n==6 || n==
//НИЖНИЙ ЛЕВЫЙ СЕГМЕНТ
{
pixels.setPixelColor(9+offset, pixels.Color(r,g,b));
pixels.setPixelColor(10+offset, pixels.Color(r,g,b));
pixels.setPixelColor(11+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(9+offset, pixels.Color(0,0,0));
pixels.setPixelColor(10+offset, pixels.Color(0,0,0));
pixels.setPixelColor(11+offset, pixels.Color(0,0,0));
}
if (n==0 || n==2 || n==3 || n== 5 || n==6 || n==8 || n==9)//НИЖНИЙ СЕГМЕНТ
{
pixels.setPixelColor(6+offset, pixels.Color(r,g,b));
pixels.setPixelColor(7+offset, pixels.Color(r,g,b));
pixels.setPixelColor(8+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(6+offset, pixels.Color(0,0,0));
pixels.setPixelColor(7+offset, pixels.Color(0,0,0));
pixels.setPixelColor(8+offset, pixels.Color(0,0,0));
}
if (n==0 || n==1 || n==3 || n==4 || n==5 || n==6|| n==7 || n==8 || n==9)//НИЖНИЙ ПРАВЫЙ СЕГМЕНТ
{
pixels.setPixelColor(3+offset, pixels.Color(r,g,b));
pixels.setPixelColor(4+offset, pixels.Color(r,g,b));
pixels.setPixelColor(5+offset, pixels.Color(r,g,b));
}
else
{
pixels.setPixelColor(3+offset, pixels.Color(0,0,0));
pixels.setPixelColor(4+offset, pixels.Color(0,0,0));
pixels.setPixelColor(5+offset, pixels.Color(0,0,0));
}
pixels.show();
}
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& address)
{
//Serial.println("sending NTP packet...");
// set all bytes in the buffer to 0
memset(packetBuffer, 3, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udp.beginPacket(address, 123); //NTP requests are to port 123
udp.write(packetBuffer, NTP_PACKET_SIZE);
udp.endPacket();
}
Корпус и диффузоры сегментов напечатаны на 3d принтере. Единственное, совершил глупость - корпус распечатал черным, а сегменты - белым и днем белые сегменты выделяются на черном фоне. Боялся, если сделать корпус белого цвета, будет фоновая засветка. Надо было пару лицевых слоев корпуса напечатать белым, а остальное - черным. Цветовая температура в сегменте ровная и четкая, просто огонь)))
https://cloud.mail.ru/public/JCJK/36cbjpAXT