Часы из ардуино

Светодиодные часы на Arduino

Такие часы очень оригинально будут смотреться на стене, они имеют в наличии светодиодные стрелки имитирующие стрелочные часы, LED часы по центру и красивую фоновую RGB-подсветку. Выполнение такой самоделки сложно назвать простым, но потраченное время и силы не будут упущены зря.
Материалы для корпуса:
— Чёрные акриловые пластины 300х300х3 мм 3шт
— Прозрачная акриловая подсветка 300х300х3 мм 1шт
— Средство полировки акриловых пластин
— Клей
— Распорные втулки 15 мм с резьбой м3 20 шт
— Винты м3 с шайбами 20 шт
— Картинная рамка 300х300 мм 1шт
Электронные материалы:
— Сдвиговый регистр CD74HC595 8шт
— LED драйвер TLC5940 1шт
— Часы реального времени (RTC) DS1307 1шт
— Линейный регулятор LM317 1шт
— Биполярный транзистор BD139 8шт
— Электролитический конденсатор 1 мкФ 2шт
— Конденсатор 0.1 мкФ 1шт
— Резисторы 120 Ом 60шт
— Резисторы 10 кОм 9шт
— Резистор 2 кОм 1шт
— Резисторы 1 кОм 9шт
— Резистор 330 Ом 1шт
— Светодиоды 480шт
— 4-х разрядный светодиодный цифровой индикатор (с общими анодами) 1шт
— Светодиодная RGB-лента (с общим анодом) 1шт (длинной под окружность циферблата)
— Модуль Arduino Mega ADK (Rev3) 1шт
— Батарея питания 12 В 1шт
Шаг первый. Изготовление корпуса.
Для начала в акриловые пластины разрезают и просверливают по чертежу. Далее , происходит склеивание корпусной передней чёрной пластины с соединительной частью (прозрачной), и с пластиной под светодиоды.
Шаг второй. Окончание работы над корпусом.
Для лучшей устойчивости автор приклеивает одну акриловую пластину к задней части картинной рамки, стекло с рамки при этом предварительно вынимается и больше не понадобится.
Четыре втулки 15 мм прикручивают к пластине как на фото. Теперь, появилась возможность приклеить втулки от рамки к передней пластине. Потом эти приклеенные втулки выкручиваются для использования в будущем.
Шаг третий. Вставка светодиодов.
В первую очередь светодиоды вставляют в первый ряд отверстий ( на 1 ряд ушло 60 светодиодов). Катоды спаиваются между собой вокруг пластины с помощью медного провода 0,8мм, а аноды отгибаются в сторону. Эта процедура повторяется для 7 остальных рядов. Теперь когда аноды расположились в один столбец, они тоже спаиваются между собой. Таким образом, получилась матрица из 8 рядов и 60 столбцов.
Шаг четвёртый. Припаивание кабелей к матрице.
Для этого шага используются 8-проводные кабельные разъёмы один из них припаяли к катодам на матрице. Восемь таких разъёмов были припаяны к 60 столбцам анодов. Поскольку автор использовал 8-проводные разъёмы, он получил кабель с 64 проводами, это значит что 4 осталось, они были замотаны изолентой. Также автор рекомендует использовать семь 8-проводных и взять один 4-проводной разъем для того, чтобы получилось ровно 60.
Шаг пятый. Прикрепление индикатора.
В акриловой пластине в виде диска делают отверстие и приклеивают индикатор с заранее припаянными проводами для удобства.
Шаг шестой. Плата.
Из куска макетной платы большего размера чем требуется, отрезают 2 куска, так чтоб они входили в картинную рамку. Далее, самостоятельно изготавливают несколько коннекторов, как видно на фото ниже.

Шаг седьмой. Сборка часов.
Дальше происходит установка всех деталей в корпус согласно схеме, прикреплённой ниже. В часы автор установил заряжаемый аккумулятор 1000мА/ч чтобы они могли работать без внешнего кабеля. На Arduino устанавливают программный код, прикреплённый внизу статьи. Так, устанавливаются библиотеки для модуля часов реального времени и LED драйвер TLC5940, которые также прикреплены под статьёй. Схема с хорошим разрешением: diagram.rar (скачиваний: 294)
Такие часы, можно по желанию модернизировать сделав автоматический контроль яркости с помощью фоторезистора, или же регулировать яркость вручную с помощью потенциометра 10 кОм. Есть пространство для установки кнопки и с её помощью можно будет переключаться между разными программами. Вдобавок есть возможность поставить светодиодную ленту, которая будет подсвечивать пластиковую прозрачную часть передней панели.
Видео с частичной сборкой и примером работы часов

clock.zip (скачиваний: 328)
led.zip (скачиваний: 309)
>Подключение часов реального времени DS1302 к Arduino и дисплея 1602 i2C — часы на ардуино !

Отличительные особенности:

  • Отличительные особенности:
  • Подсчет реального времени в секундах, минутах, часах, датах месяца, месяцах, днях недели и годах с учетом высокосности текущего года вплоть до 2100 г.
  • Дополнительное ОЗУ 31 x 8 для хранения данных
  • Последовательный ввод – вывод информации для сокращения выводов микросхемы
  • Выполнение всех функций при напряжении питания 2.0-5.5 В
    — выполнение всех функций при напряжении 2.0-5.5 В на дополнительном выводе питания
  • Потребление не более 300 нA при 2.5 В питания
  • Чтение и запись информации по одному байту или потоком
  • Исполнение в 8-ми выводном корпусе DIP, а также по заказу в 8-ми выводном SOIC корпусе для поверхностного монтажа
  • Простой 3-проводной интерфейс
  • Совместимость с TTL-микросхемами (Vcc= 5V)
  • Возможность поставки в промышленном диапазоне температур: от -40°C до+85°C
  • Совместимость с DS1202
  • Отличия от DS1202:
    возможность подключения встроенной цепи подзарядки к выводу Vcc1
    два вывода питания для подключения основного и резервного источника питания
    увеличено ОЗУ на 7 байт

Описание выводов:

X1, X2 подключение кварцевого резонатора 32.768 кГц
GND общий
RST сброс
I/O ввод — вывод данных
SCLK синхронизация последовательной связи
VCC1, VCC2 выводы питания

Структурная схема DS1302:

Расположение выводов DS1302:

Общее описание:

Микросхема DS1302 содержит часы реального времени с календарем и 31 байт статического ОЗУ. Она общается с микропроцессором через простой последовательный интерфейс. Информация о реальном времени и календаре представляется в секундах минутах, часах, дне, дате, месяце и годе. Если текущий месяц содержит менее 31 дня, то микросхема автоматически определит количество дней в месяце с учетом высокосности текущего года. Часы работают или в 24-часовом или 12-часовом формате с индикатором AM/PM (до полудня/ после полудня). Подключение DS1302 к микропроцессу упрощено за счет синхронной последовательной связи. Для этого требуется только 3 провода: (1) RST (сброс), (2) I/O (линия данных) и (3) SCLK (синхронизация последовательной связи). Данные могут передаваться по одному байту или последовательностью байтов до 31. DS1302 разработан, чтобы потреблять малую мощность и сохранять данные и информацию часов при потреблении менее 1 мкВт. DS1302 — преемник DS1202. В дополнение к основным функциям хранения времени DS1202, DS1302 имеет два вывода питания для подключения основного и резервного источника питания, возможность подключения программируемой цепи заряда к выводу VCC1 и семь дополнительных байтов ОЗУ.

Подключение:

Подключение DS1307 к Arduino:

RTC DS1307 Arduino UNO
GND GND
VCC +5V
SDA A4
SCL A5

Подключение DS1302 к Arduino:

RTC DS1302 Arduino UNO
GND GND
VCC +5V
RST 6 (Можно изменить на другие в скетче)
CLK 7 (Можно изменить на другие в скетче)
DAT

(Можно изменить на другие в скетче)

Подключение DS3231 к Arduino:

RTC DS3231 Arduino UNO
GND GND
VCC +5V
SDA A4
SCL A5

Модуль DS1302 часы реального времени на Алиэкспресс http://ali.pub/1br52w

Код программы для модуля 1302 и дисплей 1602 I2C

В зависимости от того какой модуль Вы подключаете, необходимо в программе указать

Для DS1302:

time.begin(RTC_DS1302,10,13,12);

#include <virtuabotixRTC.h>

virtuabotixRTC myRTC(6, 7, 8); //CLK, DAT, RST

Программа

#include <Wire.h>

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F ,2,1,0,4,5,6,7,3, POSITIVE);

void setup() {

lcd.begin(16,2);

//myRTC.setDS1302Time(00,04, 12, 06, 18, 04, 2017);

}

void loop() {

myRTC.updateTime();

lcd.setCursor(0, 0);

lcd.print(«date: «);

lcd.print(myRTC.dayofmonth);

lcd.print(«/»);

lcd.print(myRTC.month);

lcd.print(«/»);

lcd.print(myRTC.year);

lcd.print(» «);

lcd.setCursor(0, 1);

lcd.print(«time: «);

lcd.print(myRTC.hours);

lcd.print(«:»);

lcd.print(myRTC.minutes);

lcd.print(«:»);

lcd.print(myRTC.seconds);

lcd.println(» «);

}

Так же не забываем о экономии при покупке товаров на Алиєкспресс с помощью кэшбэка

Для веб администраторов и владельцев пабликов главная страница ePN

Для пользователей покупающих на Алиэкспресс с быстрым выводом % главная страница ePN Cashback

Удобный плагин кэшбэка браузерный плагин ePN Cashback

Преимущества библиотеки:

— библиотека имеет внутренние функции аппаратной обработки протоколов передачи данных I2C и SPI, а следовательно не требует подключения дополнительных библиотек, но и не конфликтует с ними, если таковые всё же подключены.

— библиотека имеет внутренние функции программой обработки протокола передачи данных 3-Wire

— для инициализации модуля необходимо вызвать функцию begin с названием модуля.

— подключение модулей осуществляется к аппаратным выводам arduino используемой шины (за исключением 3-Wire)

— простота установки и чтения времени функциями settime и gettime

функция settime может устанавливать дату и время, как полностью, так и частично (например только минуты, или только день, и т.д.)

функция gettime работает как функция date в php, возвращая строку со временем, но если её вызвать без параметра, то функция ничего не вернёт, а время можно прочитать из переменных в виде чисел.

— библиотека расширяемая, то есть для того, чтоб она работала с новым модулем, нужно указать параметры этого модуля в уже существующих массивах файла RTC.h (тип шины, частота шины в кГц, режимы работы, адреса регистров и т.д.), как всё это сделать, описано в файле extension.txt

Таким образом добавив новый модуль в библиотеку, мы лишь увеличим область занимаемой динамической памяти на ~ 36 байт, при этом не затронув область памяти программ.

— при вызове функции begin, библиотека читает флаги регистров модуля и при необходимости устанавливает или сбрасывает их так, чтоб модуль мог работать от аккумуляторной батареи, а на программируемом выводе меандра (если таковой у модуля есть) установилась частота 1Гц, тогда этот вывод можно использовать в качестве внешнего посекундного прерывания.

— при работе с модулем DS1302 не нужны никакие резисторы на выводе GND (которые нужны для его работы с другими библиотеками этого модуля), это достигнуто тем, что для шины 3-Wire указана конкретная частота 10кГц, не зависимо от частоты CPU arduino.

— в библиотеке реализована еще одна не обязательная функция period, принимающая в качестве единственного аргумента — количество минут (от 1 до 255)

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

Функцию period достаточно вызвать один раз.

Подробное описание:

}// ОПИСАНИЯ ПАРАМЕТРОВ ФУНКЦИЙ: // // Подключение библиотеки: // #include <iarduino_RTC.h> // iarduino_RTC time(название модуля ]]); // если модуль работает на шине I2C или SPI, то достаточно указать 1 параметр, например: iarduino_RTC time(RTC_DS3231); // если модуль работает на шине SPI, а аппаратный вывод SS занят, то номер назначенного вывода SS для модуля указывается вторым параметром, например: iarduino_RTC time(RTC_DS1305,22); // если модуль работает на трехпроводной шине, то указываются номера всех выводов, например: iarduino_RTC time(RTC_DS1302, 1, 2, 3); // RST, CLK, DAT // // Для работы с модулями, в библиотеке реализованы 5 функции: // инициировать модуль begin(); // указать время settime(секунды ]]]]]); // получить время gettime(«строка с параметрами»); // мигать времем blinktime(0-не_мигать / 1-мигают_сек / 2-мигают_мин / 3-мигают_час / 4-мигают_дни / 5-мигают_мес / 6-мигает_год / 7-мигают_дни_недели / 8-мигает_полдень) // разгрузить шину period (минуты); // // Функция begin(): // функция инициирует модуль: проверяет регистры модуля, запускает генератор модуля и т.д. // // Функция settime(секунды ]]]]]): // записывает время в модуль // год указывается без учёта века, в формате 0-99 // часы указываются в 24-часовом формате, от 0 до 23 // день недели указывается в виде числа от 0-воскресенье до 6-суббота // если предыдущий параметр надо оставить без изменений, то можно указать отрицательное или заведомо большее значение // пример: settime(-1, 10); установит 10 минут, а секунды, часы и дату, оставит без изменений // пример: settime(0, 5, 13); установит 13 часов, 5 минут, 0 секунд, а дату оставит без изменений // пример: settime(-1, -1, -1, 1, 10, 15); установит дату 01.10.2015 , а время и день недели оставит без изменений // // Функция gettime(«строка с параметрами»): // функция получает и выводит строку заменяя описанные ниже символы на текущее время // пример: gettime(«d-m-Y, H:i:s, D»); ответит строкой «01-10-2015, 14:00:05, Thu» // пример: gettime(«s»); ответит строкой «05» // указанные символы идентичны символам для функции date() в PHP // s секунды от 00 до 59 (два знака) // i минуты от 00 до 59 (два знака) // h часы в 12-часовом формате от 01 до 12 (два знака) // H часы в 24-часовом формате от 00 до 23 (два знака) // d день месяца от 01 до 31 (два знака) // w день недели от 0 до 6 (один знак: 0-воскресенье, 6-суббота) // D день недели наименование от Mon до Sun (три знака: Mon Tue Wed Thu Fri Sat Sun) // m месяц от 01 до 12 (два знака) // M месяц наименование от Jan до Dec (три знака: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) // Y год от 2000 до 2099 (четыре знака) // y год от 00 до 99 (два знака) // a полдень am или pm (два знака, в нижнем регистре) // A полдень AM или PM (два знака, в верхнем регистре) // строка не должна превышать 50 символов // // если требуется получить время в виде цифр, то можно вызвать функцию gettime() без параметра, после чего получить время из переменных // seconds секунды 0-59 // minutes минуты 0-59 // hours часы 1-12 // Hours часы 0-23

Очередные часики с 7-сигментным индикатором на TM1637 и модулем часов реального времени DS3231, с возможностью установки времени кнопками.

ниже код из видео

>Как все подключено:

>Железки на али:

Индикатор на TM1637
Часы DS3231
клон Arduino UNO

Код:

#include <Wire.h> #include «TM1637.h» // http://www.seeedstudio.com/wiki/File:DigitalTube.zip // 7сигментный индикатор #define CLK 6 #define DIO 7 #define brightness 6 // яркость, от 0 до 7 // кнопки #define keyHor 5 #define keyMin 4 #define keyPL 3 TM1637 tm1637(CLK,DIO); #define DS3231_I2C_ADDRESS 0x68 volatile boolean flag; ///// часы .. byte decToBcd(byte val){ return ( (val/10*16) + (val%10) ); } byte bcdToDec(byte val){ return ( (val/16*10) + (val%16) ); } void setDateDs3231(byte second, // 0-59 byte minute, // 0-59 byte hour, // 1-23 byte dayOfWeek, // 1-7 byte dayOfMonth, // 1-28/29/30/31 byte month, // 1-12 byte year) // 0-99 { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); Wire.write(decToBcd(second)); Wire.write(decToBcd(minute)); Wire.write(decToBcd(hour)); Wire.write(decToBcd(dayOfWeek)); Wire.write(decToBcd(dayOfMonth)); Wire.write(decToBcd(month)); Wire.write(decToBcd(year)); Wire.endTransmission(); } void getDateDs3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS3231_I2C_ADDRESS, 7); *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 setINT(){ //включает выход SQW, который вроде выключен по умолчанию Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0x0E); Wire.write(0x0); Wire.endTransmission(); } void blink() { digitalWrite(13, !digitalRead(13)); flag = !flag; tm1637.point(flag); } void setup() { // Serial.begin(9600); Wire.begin(); pinMode(13, OUTPUT); pinMode(keyHor, INPUT_PULLUP); pinMode(keyMin, INPUT_PULLUP); pinMode(keyPL, INPUT_PULLUP); tm1637.init(); tm1637.set(brightness); setINT(); attachInterrupt(0, blink, CHANGE); } void loop(){ // читаем время из модуля byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year); // забиваем массив значениями для отпарвки на экран int8_t TimeDisp; TimeDisp = hour / 10; TimeDisp = hour % 10; TimeDisp = minute / 10; TimeDisp = minute % 10; // обработка кнопок if (!digitalRead(keyHor) && !digitalRead(keyPL)){ // часы second = 0; // сбрасываем секунды hour++; // пребавляем единицу к часам if (hour > 23) hour = 0; // если вылезли за границы присваеваем 0 setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); // пишим в модуль delay(200); } if (!digitalRead(keyMin) && !digitalRead(keyPL)){ // минуты second = 0; minute++; if (minute > 59) minute = 0; setDateDs3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); delay(200); } // отправляем массив на экран tm1637.display(TimeDisp); }

Как это работает

Принцип очень простой. Библиотека «запускает» виртуальные часы «внутри» контроллера и предоставляет возможность синхронизировать их множеством способов, на выбор. Вы можете выбрать тот способ, который вам больше подходит. Поскольку Arduino Mega Server это сетевое устройство, то был выбран вариант синхронизации часов через сеть с серверами точного времени. Это могут быть сервера в Интернет или сервера в локальной сети, на которых работает соответствующая служба. Например, в базовом варианте AMS часы синхронизируются с сервером MajorDoMo, и для этого ничего настраивать не нужно, всё работает «из коробки».
Итак, для того, чтобы это заработало, нужно в начале скетча подключить соответствующие библиотеки.
#include <SPI.h> #include <Ethernet.h> #include <EthernetUdp.h> #include <Time.h>
Файл Time.h это собственно библиотека для работы со временем, а остальные файлы необходимы для работы с сетью и для синхронизации времени по протоколу NTP (библиотека Ethernet тоже должна быть у вас установлена).

Далее, вам нужно указать IP-адрес сервера, с которым вы хотите синхронизировать время
IPAddress timeServer(192, 168, 2, 8); // это адрес MajorDoMo по умолчанию
и соответствующий порт
unsigned int localPort = 8888;
но тут есть один момент: порт 8888 подходит для синхронизации в локальной сети, а в Интернет большинство серверов по нему не отвечает, поэтому, если вы планируете синхронизировать время с серверами точного времени в Интернет, то лучше установить порт 123:
unsigned int localPort = 123;
осталось только указать временную зону
const int timeZone = 4;
и создать объект EthernetUDP
EthernetUDP Udp;
На этом подготовительные операции можно считать законченными и можно описывать нужную вам функциональность работы со временем. Функция инициализации:
void rtcInit() { Udp.begin(localPort); Serial.println(«Waiting for NTP sync…»); setSyncProvider(getNtpTime); }
Здесь нужно обратить внимание на функцию
setSyncProvider(getNtpTime);
Эта функция устанавливает источник синхронизации времени (в данном случае это NTP синхронизация через сеть). Но это может быль любой другой источник, например, физический модуль RTC. Выполнение этой функции приводит к установке источника синхронизации (на будущее) и, одновременно, к самой синхронизации времени через этот источник. Именно в момент выполнения этой функции у вас в системе «появляется» точное время.
В самой библиотеке есть ещё одна интересная функция,
setSyncInterval(interval);
которая позволяет задать нужный интервал между синхронизациями (задаётся в секундах, сами синхронизации происходят автоматически, без какого-либо участия с вашей стороны).

Теперь вы можете пользоваться точным временем внутри скетча Ардуино, например, выводить в Serial монитор события не просто, а привязанными к конкретному точному времени. Делается это при помощи функции timeStamp():
void timeStamp() { serialRTC(); Serial.print(» «); }
которая является обёрткой для функции serialRTC():
void serialRTC() { Serial.print(year()); Serial.print(«-«); printDigits(month()); Serial.print(«-«); printDigits(day()); Serial.print(» «); printDigits(hour()); Serial.print(«:»); printDigits(minute()); Serial.print(«:»); printDigits(second()); }
Разбор механизма передачи и отображения времени в веб-интерфейсе AMS выходит за рамки данного повествования и достоин отдельной статьи и, если будет интерес, то можно будет написать продолжение и во всех подробностях объяснить, как происходит «магия» отображения времени в веб-интерфейсе Arduino Mega Server.

Собственно, всё. Так были организованы виртуальные часы реального времени в AMS вплоть до 0.12 версии включительно и так же вы можете организовать работу с точным временем в своих проектах, даже если у вас нет физического модуля часов реального времени. Но это ещё не конец истории, а скорее, только начало.
Полный код модуля RTC из Arduino Mega Server 0.12/*
Modul Virtual RTC
part of Arduino Mega Server project
*/
// Virtual RTC
IPAddress timeServer(192, 168, 2, 8);
unsigned int localPort = 8888; // local port to listen for UDP packets
EthernetUDP Udp;
const int timeZone = 4;
time_t prevDisplay = 0; // when the digital clock was displayed
void rtcInit() {
Udp.begin(localPort);
Serialprint(«Waiting for NTP sync… \n»);
setSyncProvider(getNtpTime);
modulRtc = 1;
}
void rtcWorks() {
if (timeStatus() != timeNotSet) {
if (now() != prevDisplay) { // update the display only if time has changed
setLifer();
prevDisplay = now();
//digitalClockDisplay();
}
}
}
void printDigits(int digits) {
if(digits < 10) {
Serial.print(‘0’);
}
Serial.print(digits);
}
void serialRTC() {
Serial.print(year());
Serial.print(«-«);
printDigits(month());
Serial.print(«-«);
printDigits(day());
Serial.print(» «);
printDigits(hour());
Serial.print(«:»);
printDigits(minute());
Serial.print(«:»);
printDigits(second());
}
void timeStamp() {
serialRTC();
Serial.print(» «);
}
void printRTC(){
serialRTC();
Serial.println();
}
// NTP code
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer; //buffer to hold incoming & outgoing packets
#ifdef RTC_FEATURE
time_t getNtpTime() {
while (Udp.parsePacket() > 0); // discard any previously received packets
Serialprint(«Transmit NTP request\n»);
sendNTPpacket(timeServer);
uint32_t beginWait = millis();
while (millis() — beginWait < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serialprint(«Receive NTP response\n»);
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer << 24;
secsSince1900 |= (unsigned long)packetBuffer << 16;
secsSince1900 |= (unsigned long)packetBuffer << 8;
secsSince1900 |= (unsigned long)packetBuffer;
return secsSince1900 — 2208988800UL + timeZone * SECS_PER_HOUR;
}
}
Serialprint(«No NTP response\n»);
return 0; // return 0 if unable to get the time
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address) {
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer = 0b11100011; // LI, Version, Mode
packetBuffer = 0; // Stratum, or type of clock
packetBuffer = 6; // Polling Interval
packetBuffer = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer = 49;
packetBuffer = 0x4E;
packetBuffer = 49;
packetBuffer = 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();
}
#endif
// Duration
void showDuration(time_t duration) {
// prints the duration in days, hours, minutes and seconds
Serialprint(» (duration «);
if(duration >= SECS_PER_DAY){
Serial.print(duration / SECS_PER_DAY);
Serialprint(» day «);
duration = duration % SECS_PER_DAY;
}
if(duration >= SECS_PER_HOUR){
Serial.print(duration / SECS_PER_HOUR);
Serialprint(» hour «);
duration = duration % SECS_PER_HOUR;
}
if(duration >= SECS_PER_MIN){

Serial.print(duration / SECS_PER_MIN);
Serialprint(» min «);
duration = duration % SECS_PER_MIN;
}
Serial.print(duration);
Serialprint(» sec) \n»);
}
void checkEvent(time_t* prevEvent) {
time_t duration = 0;
time_t timeNow = now();
if (*prevEvent > 0) {
duration = timeNow — *prevEvent;
}
if (duration > 0) {
showDuration(duration);
}
*prevEvent = timeNow;
}

Физическое подключение

Теперь давайте поговорим о том, как физически подключить модуль RTC к Arduino Mega Server или к вашему проекту на Ардуино. Сразу скажу, что это очень просто и вам понадобятся всего два резистора и несколько проводов.
Подключение тривиально: вам нужно найти на своём модуле четыре контакта — GND («земля»), VCC (напряжение питания), SCL (синхросигнал), SDA (данные). Остальные контакты используются в редких и специфических случаях и вы на них можете не обращать внимания.

Итак, вывод GND подключаем к «земле», вывод VCC — к напряжению питания контроллера. Здесь всё просто и никаких вопросов возникать не должно.
С остальными выводами дело обстоит ненамного сложнее. Модуль RTC общается с контроллером по интерфейсу I2C, у которого всего два провода: синхронизация и данные и в контроллерах Arduino уже предусмотрены контакты для подключения этого интерфейса. У Arduino Uno это A4 (SDA) и A5 (SCL), а у arduino Mega это D20 (SDA) и D21 (SCL).

Единственная тонкость заключается в том, что выводы SCL и SDA нужно «подтянуть» к источнику питания через резисторы 4,7 КОм. Если у вас нет точно такого номинала, то можно использовать резисторы из диапазона 2 КОм — 10 КОм.

Программная поддержка

Теперь осталось только дописать поддержку модуля в коде AMS или вашего проекта. Как я уже сказал, это будет очень просто потому, что с модулем будет работать всё та же библиотека Time Library. Правда нам нужно будет добавить ещё одну библиотеку, а именно DS1307RTC Library. Её тоже распаковываем и помещаем в стандартную папку для библиотек:
\аrduino\libraries\
Добавляем в код вашего скетча следующие строки
#include <Wire.h> #include <DS1307RTC.h>
Теперь мы во всеоружии и можем приступать к написанию кода самого скетча, работающего с физическим модулем RTC. В функции
void rtcInit() { Udp.begin(localPort); Serial.println(«Waiting for NTP sync…»); setSyncProvider(getNtpTime); }
заменяем строку
setSyncProvider(getNtpTime);
на
setSyncProvider(RTC.get);
и внутреннее время Arduino Mega Server (или вашего контроллера) будет синхронизироваться с «железным» контроллером RTC, а не с серверами в Интернет или локальной сети. Таким образом, вызывая функции setSyncProvider(getNtpTime) и setSyncProvider(RTC.get) вы можете манипулировать источниками синхронизации времени и синхронизировать время так, как вам будет угодно, в зависимости от различных условий.
Ещё одна функция, о которой вам необходимо знать, это
if (timeStatus() != timeNotSet) { }
которая позволяет узнать синхронизировано ли время и в зависимости от данного условия предпринять нужные действия.

Тонкий момент

Нужно различать две вещи: время, идущее в «железном» модуле RTC и время, идущее в вашем контроллере. Это не одно и то же. «Главным» для вас является время в контроллере, а время в модуле является лишь источником для синхронизации.
Но! поскольку время в физическом RTC тоже постепенно «уходит», то его тоже нужно подстраивать, синхронизируя с более точными источниками, например, с серверами в Интернет.
Поэтому, оптимальный алгоритм должен быть такой: если есть возможность, то синхронизируем все часы с серверами в Интернет, если сеть недоступна, то начинаем синхронизировать время в контроллере с модулем RTC, как только появляется сеть — переходим опять на синхронизацию через Интернет.
Если вы находитесь в экстремальных условиях, без доступа к каким-либо источникам синхронизации, то можно вручную время от времени корректировать ход «железных» часов.
Давайте, для примера, рассмотрим функцию синхронизации внутренних часов контроллера и модуля RTC через сеть:
void rtcSync() { setSyncProvider(getNtpTime); Serial.println(«…getNtpTime…»); if (timeStatus() != timeNotSet) { Serial.println(«…set!…»); time_t t = getNtpTime(); RTC.set(t); setSyncProvider(RTC.get); } }
Здесь мы сначала получаем точное время по сети
setSyncProvider(getNtpTime);
затем, в случае удачи, устанавливаем его в модуль RTC
RTC.set(t);
а затем уже из этого модуля устанавливаем время контроллера
setSyncProvider(RTC.get);

Что за идея

Ранее мы делали один сложный проект с цифровыми часами, о котором мы расскажем в следующих уроках, и нашли в процессе несколько проблем. После этого мы решили поделиться этой проблемой со всеми. Основная проблема в том как оценивается длительность секунды.

По факту — сделать правильную секунду в цифровых часах не так просто. Нужно правильно работать с циклами. Мы нашли много комментариев на англоязычных сайтах:

На скриншоте выше видно, что код реализован таким образом, что теперь инкремент s будет выполняться каждую 1 секунду и не больше, в зависимости от времени выполнения цикла loop{}.

В связи с этим резисторы и потенциометры мы полностью удалили.

Кнопки настройки времени вы можете использовать встроенные в микросхему ATmega328P.

pinMode(hs, INPUT_PULLUP) избегает использования внешнего Pullup. Подробнее о INPUT_PULLUP читайте в нашем Справочнике программиста Ардуино.

Избегайте потенциометра ЖК-дисплея.

Контрастность ЖК-дисплея может быть установлена с помощью сигнала PWM (Широтно-импульсная модуляция (ШИМ, англ. pulse-width modulation (PWM))) Arduino.

То же самое для подсветки, которая питается сигналом ШИМ (PWM) Arduino, поэтому её можно установить как вкл/выкл с помощью Arduino.

Код

Код проекта вы можете скачать или скопировать ниже. Код содержит комментарии. Обычно мы рекомендуем копировать код из скачанного файла, т.к. при копировании могут выявляться некоторые ошибки.

Также не забываем, что мы в самом начале подключаем библиотеку LiquidCrystal, которую вы можете скачать в разделе Библиотеки на нашем сайте.

/* ### Самые простые часы на Arduino UNO ### Для проекта часов нужны только жк-дисплей 16х2 LCD и 2 кнопки Никаких потенциометров для контраса, никаких резисторов Функции кнопок: — короткое нажатие одной из кнопок включает подсветку на 30 с Настройка времени — Нажмите H для увеличения Часов — Нажмите M для увеличения Минут и сброса секунд */ #include «LiquidCrystal.h» // Определяем соединение ЖК-дисплея с цифровыми контактами const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // Настройка контрастности ЖК int cs=9;// пин 9 для контраста ШИМ const int contrast = 100;// контраст по умолчанию // Начальное отображение времени 12:59:45 PM int h=12; int m=59; int s=45; int flag=1; //PM // Кнопки установки времени int button1; int button2; // Определение пинов для Кнопок установки времени int hs=0;// pin 0 для настройки Часов int ms=1;// pin 1 для настройки Минут // Тайм-аут подсветки const int Time_light=150; int bl_TO=Time_light;// Тайм-аут подсветки int bl=10; // Пин подсветки const int backlight=120; // НЕ БОЛЕЕ 7mA !!! // Для точного считывания времени используйте часы реального времени Arduino, а не только задержку delay() static uint32_t last_time, now = 0; // RTC void setup() { lcd.begin(16,2); pinMode(hs,INPUT_PULLUP);// избегать внешних Pullup резисторов для кнопки 1 pinMode(ms,INPUT_PULLUP);// и кнопки 2 analogWrite(cs,contrast);// Настроить контрастность VO analogWrite(bl,backlight);// Включить подсветку now=millis(); // читать начальное значение RTC } void loop() { lcd.begin(16,2);// каждую секунду // Обновить ЖК-дисплей // Вывести время TIME в Hour, Min, Sec + AM/PM (часы, минуты, секунды) lcd.setCursor(0,0); lcd.print(«Time «); if(h<10)lcd.print(«0»);// всегда 2 цифры lcd.print(h); lcd.print(«:»); if(m<10)lcd.print(«0»); lcd.print(m); lcd.print(«:»); if(s<10)lcd.print(«0″); lcd.print(s); if(flag==0) lcd.print(» AM»); if(flag==1) lcd.print(» PM»); lcd.setCursor(0,1);// для Line 2 lcd.print(«Precision clock»); // улучшенная замена delay(1000) // гораздо лучшая точность, менее зависимая от времени выполнения цикла for ( int i=0 ;i<5 ;i++)// сделать 5-кратный цикл 200 мс, для более быстрого ответа кнопок { while ((now-last_time)<200) //задержка delay 200ms { now=millis(); } // внутренний цикл 200ms last_time=now; // готовим следующий цикл // read Setting Buttons (читаем кнопки настройки) button1=digitalRead(hs);// Read Buttons button2=digitalRead(ms); //Время подсветки bl_TO—; if(bl_TO==0) { analogWrite(bl,0);// ВЫКЛ подсветки bl_TO++; } // Нажмите что-либо, чтобы активировать подсветку if( ((button1==0)|(button2==0)) & (bl_TO==1) ) { bl_TO=Time_light; analogWrite(bl,backlight); // дождитесь отпускания кнопки while ((button1==0)|(button2==0)) { button1=digitalRead(hs);// Read Buttons button2=digitalRead(ms); } } else // Поведение Кнопки 1 или Кнопки 2 пока подсветка ВКЛ { if(button1==0){ h=h+1; bl_TO=Time_light; analogWrite(bl,backlight); } if(button2==0){ s=0; m=m+1; bl_TO=Time_light; analogWrite(bl,backlight); } /* —- управлять секундами, минутами, часами am / pm —-*/ if(s==60){ s=0; m=m+1; } if(m==60) { m=0; h=h+1; } if(h==13) { h=1; flag=flag+1; if(flag==2)flag=0; } if((button1==0)|(button2==0))// Обновить дисплей, если нажата кнопка { // Обновить ЖК // Вывести время TIME в часах, минутах, секундах + AM/PM lcd.setCursor(0,0); lcd.print(«Time «); if(h<10)lcd.print(«0»);// всегда 2 цифры lcd.print(h); lcd.print(«:»); if(m<10)lcd.print(«0»); lcd.print(m); lcd.print(«:»); if(s<10)lcd.print(«0″); lcd.print(s); if(flag==0) lcd.print(» AM»); if(flag==1) lcd.print(» PM»); lcd.setCursor(0,1);// для Line 2 lcd.print(«Precision clock»); } } // end if else }// end for // outer 1000ms loop (завершение цикла) s=s+1; //увеличение секунд // —- управлять секундами, минутами, часами + am/pm —- if(s==60){ s=0; m=m+1; } if(m==60) { m=0; h=h+1; } if(h==13) { h=1; flag=flag+1; if(flag==2)flag=0; } // Loop end (конец цикла) }