→ Arduino подключение часов реального времени ds3231. DS3231 – подключение часов реального времени. Посты по урокам

Arduino подключение часов реального времени ds3231. DS3231 – подключение часов реального времени. Посты по урокам

Модуль DS3231 (RTC, ZS-042) — представляет собой недорогую плату с чрезвычайно точными часами реального времени (RTC), с температурной компенсацией кварцевого генератора и кристалла. Модуль включает в себя литиевую батарею, которая поддерживает бесперебойную работу, даже при отключении источник питания. Интегрированный генератор улучшить точность устройства и позволил уменьшить количество компонентов.

Технические параметры

Напряжение питания: 3.3В и 5В
Чип памяти: AT24C32 (32 Кб)
Точность: ± 0.432 сек в день
Частота кварца:32.768 кГц
Поддерживаемый протокол: I2C
Габариты: 38мм x 22мм x 15мм

Общие сведения

Большинство микросхем, таких как DS1307 используют внешний кварцевый генератор частотой 32кГц, но в них есть существенный недостаток, при изменении температуры меняется частота кварца, что приводит к погрешности в подсчете времени. Эта проблема устранена в чипе DS3231, внутрь которого установили кварцевый генератор и датчик температуры, который компенсирует изменения температуры, так что время остается точным (при необходимости, данные температуры можно считать). Так же чип DS3231 поддерживает секунды, минуты, часы, день недели, дата, месяц и год информацию, а так же следит за количеством дней в месяце и делает поправку на високосный год. Поддерживает работу часов в двух форматов 24 и 12, а так-же возможно запрограммировать два будильника. Модуль работает по двух проводной шине I2C.


Теперь немного о самом модуле, построен он на микросхеме DS3231N. Резисторная сборка RP1 (4.7 кОм), необходима для подтяжки линий 32K, SQW, SCL и SDA (кстати, если используется несколько модулей с шиной I2C, необходимо выпаять подтягивающие резисторы на других модулях). Вторая сборка резисторов, необходима для подтяжки линий A0, A1 и A2, необходимы они для смены адресации микросхемы памяти AT24C32N. Резистор R5 и диод D1, служат для подзарядки батарее, в принципе их можно выпаять, так как обычной батарейки SR2032 хватает на годы. Так же установлена микросхема памяти AT24C32N, это как бы бонус, для работы часов RTC DS3231N в ней нет необходимости. Резистор R1 и светодиод Power, сигнализируют о включении модуля. Как и говорилось, модуль работает по шине I2C, для удобства эти шины были выведены на два разъема J1 и J2, назначение остальных контактов, можно посмотреть ниже.Назначение J1
32K: выход, частота 32 кГц
SQW: выход
SDA: линия данных (Serial Dфta)
VCC: «+» питание модуля
GND: «-» питание модуля Назначение J2
SCL: линия тактирования (Serial CLock)
SDA: линия данных (Serial Data)
VCC: «+» питание модуля
GND: «-» питание модуля


Немного расскажу, о микросхеме AT24C32N, это микросхема с 32к памятью (EEPROM) от производителя Atmel, собранная в корпусе SOIC8, работающая по двухпроводной шине I2C. Адрес микросхемы 0x57, при необходимости легко меняется, с помощью перемычек A0, A1 и A2 (это позволяет увеличить количество подключенных микросхем AT24C32/64). Так как чип AT24C32N имеет, три адресных входа (A0, A1 и A2), которые могут находится в двух состояния, либо лог «1» или лог «0», микросхеме доступны восемь адресов. от 0x50 до 0x57.

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

Необходимые детали:
Arduino UNO R3 x 1 шт.
Часы реального времени на DS3231, RTC, SPI, AT24C32 x 1 шт.
Провод DuPont, 2,54 мм, 20 см, F-M (Female — Male) x 1 шт.
Кабель USB 2.0 A-B x 1 шт.

Подключение:
В данном примере буду использовать только модуль DS3231 и Arduino UNO R3, все данные будут передаваться в «Мониторинг порта». Схема не сложная, необходимо всего четыре провода, сначала подключаем шину I2C, SCL в A4 (Arduino UNO) и SDA в A5 (Arduino UNO), осталось подключить питание GND к GND и VCC к 5V (можно записать и от 3.3В), схема собрана, теперь надо подготовить программную часть.

Библиотеки работающий с DS3231 нет в среде разработке IDE Arduino, необходимо скачать «DS3231 » и добавить в среду разработки Arduino.

Установка времени DS3231
При первом включении необходимо запрограммировать время, откройте пример из библиотеки DS3231 «Файл» -> «Примеры» -> «DS3231» -> «Arduino» -> «DS3231_Serial_Easy», или скопируйте код снизу

/* Тестирование производилось на Arduino IDE 1.8.0 Дата тестирования 31.08.2018г. */ #include // Подключаем библиотеку Wire DS3231 rtc(SDA, SCL); // Инициализация DS3231 void setup() { Serial.begin(115200); // Установка последовательного соединения rtc.begin(); // Инициализировать rtc // Установка времени rtc.setDOW(FRIDAY); // Установить день-недели rtc.setTime(16, 29, 0); // Установить время 16:29:00 (формат 24 часа) rtc.setDate(31, 8, 2018); // Установить дату 31 августа 2018 года } void loop() { Serial.print(rtc.getDOWStr()); // Отправляем день-неделя Serial.print(" "); Serial.print(rtc.getDateStr()); // Отправляем дату Serial.print(" -- "); Serial.println(rtc.getTimeStr()); // Отправляем время delay (1000); // Задержка в одну секунду }

Тестирование производилось на Arduino IDE 1.8.0

Дата тестирования 31.08.2018г.

#include // Подключаем библиотеку Wire

DS3231 rtc (SDA , SCL ) ; // Инициализация DS3231

void setup ()

Serial . begin (115200 ) ; // Установка последовательного соединения

rtc . begin () ; // Инициализировать rtc

// Установка времени

rtc . setDOW (FRIDAY ) ; // Установить день-недели

rtc . setTime (16 , 29 , 0 ) ; // Установить время 16:29:00 (формат 24 часа)

void loop ()

Serial . print (rtc . getDOWStr () ) ; // Отправляем день-неделя

Serial . print (" " ) ;

Serial . print (rtc . getDateStr () ) ; // Отправляем дату

Serial . print (" -- " ) ;

Serial . println (rtc . getTimeStr () ) ; // Отправляем время

delay (1000 ) ; // Задержка в одну секунду

Загружаем скетч в контроллер Arduino и открываем «Мониторинг порта»

Сегодня мы продолжим поиски идеальной микросхемы часов реального времени (RTC). Часы будем изготавливать на основе . Индикация будет использоваться более удобная для разработки - LCD дисплей, на котором будет отображаться вся информация сразу кроме настроек. В таком виде часы удобно использовать как настольный вариант.

Итак, рассмотрим саму микросхему DS3231. DS3231 - это часы реального времени с экстремально точным ходом (подобрали же производители словечко) благодаря встроенному кварцевому резонатору с температурной компенсацией. Интерфейс передачи данных - I 2 C. В этой микросхеме есть также вход для напряжения резервной батареи, при отключении основного питания микросхема автоматически переключается на работу от резервной батареи, точность хода от резервной батареи не нарушается. Весьма радует, не правда ли? В DS3231 поддерживается подсчет секунд, минут, часов, дней месяца (даты), дней недели, месяцев и лет (с учетом високосного года для месяцев). Поддерживается работа в 12 и 24 часовом формате. Имеется 2 будильника с возможностью их настройки и отслеживания состояния. Подстройка точности температурной компенсации. А также два выхода - на 32 кГц (выход составляет 32.768 кГц) и программируемый выход от 1 Гц до 8.192 кГц. Имеется также вывод сброса - RST. микросхема часов реального времени выпускается в корпусе SO-16. Корпус достаточно крупный, но если учитывать что внутри уже имеется кварц, да еще и температурно компенсируемый, то мне кажется, с размерами тут все отлично. У DS3231 есть близнец в виде DS3232, у которого, правда, на 2 ножки больше. Все это очень напоминает продукцию компании NXP - микросхемы часов PCA2129 и PCF2129. Аналогично температурно компенсируемый встроенных кварцевый резонатор, оба такие же близнецы только с разным количеством n.c. выводов и схожими функциями относительно DS3231 помимо хронометрожа времени.

RTC DS3231 имеются в продаже в виде модулей с необходимой обвязкой, а также до комплекта микросхемой EEPROM, которая чаще всего и даром не нужно, только веса добавляет:

Кроме необходимых деталей на плате модуля есть также светодиод, функция которого - индикация подключения питания к выводам. Наверно просто так доставили, для красоты.

Что важно знать при работе с такой микросхемой часов реального времени, так это как же извлечь из нее данные или записать их туда. Часы имеют интерфейс I 2 C. Для того чтобы осуществить запись данных (а это нужно и для того чтобы прочитать данные) нужно передать условие старта (эти команды осуществляются по средствам аппаратного или программного I 2 C для микроконтроллера), далее передать адрес микросхемы с битом записи, далее передать адрес регистра к которому будем обращаться и далее передать в этот регистр байт данных, если следом передать еще байт данных, он запишется в следующий регистр и так далее. По окончании нужно передать условие остановки. Графическое изображение выше сказанного на рисунке:

Запись данных необходима для первоначальной настройки, а также для настройки текущего времени. Далее нам нужно постоянно получать данные о текущем времени и даты. Для этого необходимо осуществлять чтение из регистров хранения этой информации. Чтение состоит из двух процедур - установить указатель на нужный регистр и прочитать его. Чтобы установить указатель на нужный регистр, нужно передать условие старта, потом передать адрес микросхемы с битом записи и байт с адресом регистра. Далее либо условие остановки и следом условие старта, либо просто рестарт. Теперь вторая процедура - непосредственно чтение из регистров. Старт передан, далее нужно отправить адрес микросхемы с битом чтения и далее считывать регистры в необходимом количестве, по окончании передать условие остановки. Если информация из регистра была прочитана, то указатель автоматически переходит на следующий за ним регистр без лишних действий со стороны микроконтроллера (мастер устройства). На рисунке проиллюстрировано все выше сказанное относительно чтения регистров по средствам I 2 C интерфейса:

Адрес микросхемы:

  • для записи - 0b11010000
  • для чтения - 0b11010001

Программно код на языке Си будет выглядеть следующим образом:

// функции с часами ======================================================================================================= // инициализация начальных установок void RTC_init(void){ i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_write); // передача адреса устройства, режим записи i2c_send_byte(0x0E); // передача адреса памяти i2c_send_byte(0b00100000); // запустить преобразование температуры и выход на 1 Гц i2c_send_byte(0b00001000); // разрешить выход 32 кГц i2c_stop_cond(); // остановка i2c } // получение времени и даты void RTC_read_time(void){ i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_write); // передача адреса устройства, режим записи i2c_send_byte(0x00); // передача адреса памяти i2c_stop_cond(); // остановка i2c i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_read); // передача адреса устройства, режим чтения sec = bcd(i2c_get_byte(0)); // чтение секунд, ACK min = bcd(i2c_get_byte(0)); // чтение минут, ACK hour = bcd(i2c_get_byte(0)); // чтение часов, ACK wday = bcd(i2c_get_byte(0)); // чтение день недели, ACK day = bcd(i2c_get_byte(0)); // чтение число, ACK month = bcd(i2c_get_byte(0)); // чтение месяц, ACK year = bcd(i2c_get_byte(1)); // чтение год, NACK i2c_stop_cond(); // остановка i2c } // установка времени void RTC_write_time(unsigned char hour1,unsigned char min1, unsigned char sec1){ i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_write); // передача адреса устройства, режим записи i2c_send_byte(0x00); // передача адреса памяти i2c_send_byte(bin(sec1)); // 0x00 секунды (целесообразно ли задавать еще и секунды?) i2c_send_byte(bin(min1)); // 0x01 минуты i2c_send_byte(bin(hour1)); // 0x02 часы i2c_stop_cond(); // остановка i2c } // установка даты void RTC_write_date(unsigned char wday, unsigned char day, unsigned char month, unsigned char year){ i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_write); // передача адреса устройства, режим записи i2c_send_byte(0x03); // передача адреса памяти i2c_send_byte(bin(wday)); // 0x03 день недели (воскресенье - 1, пн 2, вт 3, ср 4, чт 5, пт 6, сб 7) i2c_send_byte(bin(day)); // 0x04 день месяц i2c_send_byte(bin(month)); // 0x05 месяц i2c_send_byte(bin(year)); // 0x06 год i2c_stop_cond(); // остановка i2c } // чтение температуры void RTC_read_temper(void){ i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_write); // передача адреса устройства, режим записи i2c_send_byte(0x11); // передача адреса памяти i2c_stop_cond(); // остановка i2c i2c_start_cond(); // запуск i2c i2c_send_byte(RTC_adr_read); // передача адреса устройства, режим чтения t1 = i2c_get_byte(0); // чтение MSB температуры t2 = i2c_get_byte(1); // чтение LSB температуры i2c_stop_cond(); // остановка i2c t2=(t2/128); // сдвигаем на 6 - точность 0,25 (2 бита) // сдвигаем на 7 - точность 0,5 (1 бит) t2=t2*5; }

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

Да - отличной фишкой DS3231 является то, что эта же микросхема выполняет функции термометра (а то как же еще осуществлять температурную компенсацию) и возможность чтения текущей температуры. Максимальное разрешение температуры составляет 0.25 градусов Цельсия. Также период обновления температуры достаточно большой - около 1 минуты. Да нам быстро то не к чему обновлять ее.

Схема же всего устройства часов выглядит так:

Микроконтроллер был выбран Atmega8 за свою широкую распространенность и небольшую цену. Данный микроконтроллер можно использовать как в корпусе DIP-28, так и в SMD исполнении в корпусе TQFP-32. Резистор R3 необходим для предотвращения самопроизвольного перезапуска микроконтроллера в случае появления случайных помех на выводе PC6. Резистор R3 подтягивает плюс питания к этому выводу, надежно создавая потенциал на нем. Для индикации используется жидко кристаллический (ЖК или LCD) дисплей. Мною использовался дисплей 2004А - 4 строки по 20 символов больше для красоты, поэтому можно применять дисплей более привычный - 2 строки по 16 символов. ЖК дисплей подключается к микроконтроллеру по четырех битной системе. Переменный резистор R2 необходим для регулировки контраста символов на дисплее. Вращением движка этого резистора добиваемся наиболее четких для нас показаний на экране. Подсветка ЖК дисплея организована через вывод "А" и "К" на плате дисплея. Подсветка включается через резистор, ограничивающий ток - R1. Чем больше номинал, тем более тускло будет подсвечиваться дисплей. Однако пренебрегать этим резистором не стоит во избежание порчи подсветки. Кнопки S1 - S4 управляют настройками часов. Светодиод сигнализирует о том, что будильник сработал. Светодиод можно заменить на какую-либо звуковую схему. Резисторы R5 - R8 являются подтягивающими (pull-up) и необходимы для формирования прямоугольных импульсов на выводах микросхемы часов. Также это необходимо для правильной работы протокола I2C. Для питания схемы используется микросхема линейного стабилизатора L7805, ее можно заменить на отечественный аналог пяти вольтового линейного стабилизатора КР142ЕН5А, либо применить другу микросхему стабилизатора напряжения в соответствии с подключением ее в схеме (например LM317 или импульсные стабилизаторы LM2576, LM2596, MC34063 и так далее). Далее 5 вольт стабилизируются другой микросхемой - AMS1117 в исполнении, дающей на выходе 3,3 вольта. Микросхема часов, в соответствии с даташитом, питается от напряжения 3,3 вольта. Однако максимальное напряжение составляет 5,5 вольта. Поэтому Данный стабилизатор можно использовать, а можно и нет, на ваше усмотрение. Стабилизатор напряжения AMS1117 можно также заменить на исполнение ADJ (AMS1117ADJ) - то есть регулируемый вариант, задать необходимое напряжение при таком выборе необходимо будет при помощи двух резисторов, подключаемых к микросхеме в соответствии с даташитом на нее.

Схема была собрана и отлажена с применением отладочной макетной платы для микроконтроллера ATmega8:

Назначение кнопок:

  • S1 - отключает сигнал будильника, либо выходит в главное меню из любого меню настроек
  • S2 - сброс микроконтроллера
  • S3 - изменяет время или дату в меню настроек
  • S4 - вход в меню настроек и перелистывание меню

Вывод 32 кГц может использоваться для контроля частоты кварцевого резонатора. Подключаем к этому выводу частотомер или осциллограф и контролируем частоту:

Как видно из скриншота осциллограммы, частота примерно соответствует 32,768 кГц (примерно в силу ограничения разрешения измерения частоты, а "на глаз" настолько точно трудно определить).

В итоге получились часы со следующими характеристиками:

  • индикация времени
  • индикация даты
  • индикация дня недели
  • индикация активности будильника
  • 1 будильник с выходом сигнала от микроконтроллера
  • индикация температуры окружающей среды (программно реализована только положительная температура, отрицательная, думаю, нам ни к чему)
  • настройки будильника
  • настройки времени
  • настройки даты
  • LCD-дисплей с подсветкой
  • сохранение настроек и продолжение хода часов при отключении основного питания

Подытожим . Микросхема часов реального времени DS3231 является отличным решением. Точность хода сравнительно c какой-нибудь DS1307 или выше, а вот PCA/PCF2129 еще могут потягаться с ней. Среди рассмотренных мною микросхем часов реального времени данный экземпляр на сегодняшний день занимает первое место по функционалу и точности.

Для программирования микроконтроллера Atmega8 необходимо знать конфигурацию фьюз битов (скриншот сделан в программе ):

К статье прилагается прошивка для микроконтроллера Atmega8, проект схемы в программе , а также видео работы часов (в самом начале сработает будильник - загорится светодиод).

Список радиоэлементов

Обозначение Тип Номинал Количество Примечание Магазин Мой блокнот
IC1 МК AVR 8-бит

ATmega8

1 В блокнот
IC2 Часы реального времени (RTC)

DS3231

1 В блокнот
VR1 Линейный регулятор

L7805AB

1 В блокнот
VR2 Линейный регулятор

AMS1117-3.3

1 В блокнот
VD1 Выпрямительный диод

1N4148

1 В блокнот
C1 470 мкФ 1 В блокнот
C2, C3, C5, C7 Конденсатор 100 нФ 4 В блокнот
C4 Электролитический конденсатор 220 мкФ 1 В блокнот
C6, C8 Электролитический конденсатор 10 мкФ 2 В блокнот
R1 Резистор

22 Ом

1 В блокнот
R2 Подстроечный резистор 10 кОм 1 3296W-1-103LF

Зачем всё это нужно?

60сек * 60мин *24 часа * 365 дней = 31 536 000 секунд в году.

На каждый из этих миллионов 2 секунды может уходить в ту или иную сторону. 31,5 миллион делим на миллион и умножаем на 2: получаем 63 секунды в год (максимум). Приемлемый вариант? Весьма. Но 1 раз в полгода я бы синхронизировал время, чтобы оно укладывалось в 1 минуту.

Какими способами вообще можно устанавливать время на часах модуля?

Традиционно, начиная с модуля DS3107, время устанавливалось при помощи скетча для Arduino из числа примеров использования библиотеки. Алгоритм такой: открываем скетч, жмём «компилировать и закачать», и при первом запуске контроллера время устанавливается. Остался вопрос: какое время? Откуда Arduino может узнать, какое именно время устанавливать? А очень просто – время компиляции скетча. Однако с таким подходом я вижу несколько недостатков:
  • время компиляции зависит от «мощи» компьютера;
  • время закачивания зависит от скорости передачи скомпилированного скетча в плату Arduino;
  • закачанный скетч – «одноразовый» (устаревает сразу же после закачивания в Arduino).
Как можно «извернуться», чтобы обойти эти ограничения? Ну, например, зная (экспериментально установив) время компилирования, можно «загнать» часы на компьютере на это время вперёд. Потом запустить компиляцию, прошить плату, и время установится. Плюс метода – относительная простота. Минусы – относительно неудобно, относительно неточно, одноразовый способ.

Что ещё можно придумать? Можно, например, выставлять требуемое время в скетче вручную, предусмотреть кнопку, нажатие на которую в нужный момент выставит «руками» указанное время, например, через 2 минуты от текущего момента: пока «зальётся» скетч, пока подготовимся отследить вручную тот самый нужный момент нажатия кнопки, как раз та пара минут и пройдёт. А дальше, глядя на часы в компьютере, дожидаться «того самого» момента, чтобы нажать кнопку. Плюсы – сложнее предыдущего способа, но всё ещё относительно просто, однако точнее, чем первый способ. Минусы – этот способ ещё неудобнее, дольше, всё равно скетч «одноразовый».

Кто виноват и что делать?

Задав себе эти два риторических вопроса, я полез в Интернет искать, кто уже написал синхронизацию времени модуля часов с компьютером. И, как известно, кто ищет – тот всегда находит. Нашёлся вариант с . В теории всё просто: обычный «батник» парсит текущее полное время, полученное «первым» способом (потому что кроме самого времени нужна ещё и дата), увеличивает время на 2 секунды, и «гоняет» пустой цикл до момента, когда настанет это новое, «плюс_две_секундное», время, чтобы «вышвырнуть» данные в COM порт. Причём «новое плюс_две_секундное» время отслеживается другим способом (через %time%, если кому интересно). Но о «косяках» такого решения позже. Данные, «вышвырнутые» в COM порт, Arduino парсит и после этого устанавливает время в модуле. Вроде всё просто, логично и удобно. Но есть очень нехорошее слово «НО». Всё это писал вроде бы немец, и региональные стандарты в Windows у него отличаются от «наших», а в частности, дробная часть отделяется точкой, а не запятой. При запуске с отечественными региональными стандартами «батник» не работает, потому что в нём время выхода из пустого цикла описывается условием сравнения с XX:XX:XX.xxx. Ну так надо вместо точки поставить запятую – и всё, «я всё починил». А вот и не всё (можете проверить, кто ещё помнит, что за такое зло – программировать в «батниках»). Нужно исправлять «батник» более серьёзно. И я его исправил, используя «маты-перематы» и «мануалку» для DOS. «Батник» исправил, но скетч всё равно не работал – время не устанавливалось. То есть данные в порт слались, Arduino их видел, но «что-то пошло не так».

Давайте взглянем, что шлёт «батник» в Arduino и в каком формате (справочно).

Case 83: //S = second case 68: //D = Minute (Daghigheh in Persian) case 72: //H = Hour case 84: //T = Day Of Month (Tag in German) case 77: /// M = Month case 74: /// J = Year (Jahr in German)
Данные шлются в формате S**~D**~H**~T*~M**~J****~, где ~ - 2 байта перевода каретки. Итого, 31 байт. Вроде немного, пришлются данные быстро.

Однако есть и неудобство – как видим, не шлётся день недели. Только день месяца. Для реализации часов с будильниками, зависящими от дней недели, будет «косяк». День недели придётся выставлять «ручками» в скетче, что опять намекает на некоторую «одноразовость» скетча, его неполноценность.

Складывая факторы – неполноценность скетча «с завода», его отказ нормально работать, необходимость исправления «батника» для «наших» широт – я решил разрабатывать всё свое. А раз так, то я могу устранять недостатки и оптимизировать формат данных.

Software и hardware.

Для того, чтобы всё заработало, нужны 2 составляющие: программа для Windows и аппаратно-программная связка Arduino.

Сначала общие данные по протоколу обмена. Коль скоро я стал волен выбирать формат данных для пересылки, я решил, что пересылка 31 байта информации не рациональна, и сократил передаваемые данные до 4 байт. И что, хватило? Что можно поместить в 4 байта? Да, хватило. Поместилось все, что надо. Уверен, многие догадались, что это за 4 байта. Кто не догадался – процитирую фрагмент статьи из Википедии:

UNIX-время (POSIX-время) - система описания моментов во времени, принятая в UNIX и других POSIX-совместимых операционных системах. Определяется как количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года (четверг).
UNIX-время представлено целым числом, которое увеличивается с каждой прошедшей секундой без необходимости вычислений для определения года, месяца, дня, часа или минуты для удобства восприятия человеком. Современное UNIX-время согласуется с UTC - отсчет происходит в секундах СИ.

Итак, целое число, хранящее UNIX время, занимает 4 байта, чего хватит до 2 147 483 648 секунд. А потом возможны потенциальные проблемы. Почему потенциальные? Потому что это порог, при достижении которого число может быть интерпретировано, как отрицательное (что и с айфонами многих любопытных товарищей в своё время). Может, но не обязательно будет – зависит от того, растут ли руки программистов из места, предусмотренного природой. Указанное число секунд соответствует 03:14:08 19-янв-2038. До этого времени можно неспешно переходить на 64-битную версию ОС, где время станет храниться в 8-байтной переменной, чего без проблем хватит на следующие 292 миллиарда лет. Существует вероятность, что на наш век этого хватит. А потом придётся обновляться до 128-битной версии UNIX.

Какие проблемы я решил, придя к такому варианту? Первое, сильно снизил количество передаваемых байт, что на миллисекунды увеличивает точность установки времени. Здорово, правда? И второе: я (вероятно) облегчил совместимость с Linux. К моему стыду, я никак не могу привыкнуть к Linux, и пользуюсь в основном только Windows. Для этой самой Windows я могу написать программу пересылки, а для Linux – нет. Но полагаю, что в Linux можно получить значение UNIX-времени намного легче, чем в Windows, и переслать это число в COM порт.

Никаких дополнительных данных, вроде дня недели и так далее, передавать не требуется. Только UNIX время. Всё остальное делается в Arduino.

Теперь немного конкретики непосредственно о первой составляющей – программе для Windows. Программа написана в старой-доброй Delphi. При запуске всплывающее окно просит выбрать COM порт для отправки данных. Выбираем. Остальные настройки следует оставить «дефолтными».

Как работает программа? Она пересчитывает из формата времени Windows данные для формата UNIX, то есть число секунд с полуночи 1 января 1970 года. Затем добавляет 3 секунды и «впадает» в пустой цикл (очевидно, длительностью уже менее тех самых добавочных 3 секунд), выход из которого происходит в нужное количество секунд, как можно ближе к 000 миллисекундам. Иначе говоря, отслеживается наступление самого начала той секунды времени, значение которого должно будет переслаться в Arduino. Согласитесь, пересылать данные о том, что, например, сейчас XXXXXXXXX5 секунд тогда, когда на самом деле уже, например, XXXXXXXXX5 и 756 тысячных (например) секунд, было бы не правильным. Именно для этого нужно отслеживать самое начало секунды для старта передачи данных. После передачи данных программа дружелюбно сообщает статус «Done:)». На этом миссия программы завершается.


Вторая составляющая – аппаратно-программная часть – Arduino. Существует 2 разновидности «железа» для этого проекта: «полная» версия с экраном и кнопкой, и «урезанная» версия для быстрой установки времени модуля, собранная из «г**на и палок». Про их отличия – ниже. «Полная» версия состоит из Arduino Nano, экрана 1602 с «переходником» с I2C в экран, опциональной кнопкой ресета Arduino и пин-хедера(female) для подключения модуля часов. Также, опционально, из корпуса девайса с «няшной» наклейкой. «Урезанная» версия состоит из Arduino (Uno, Nano, Pro Mini + «правильный» переходник на USB с DTR) и 4 проводов для подключения модуля часов.



Как видно из схем, «полная» версия, в дополнение к «урезанной», содержит кнопку для reset"а и экран 1602 с «переходником». Обе версии абсолютно одинаковы по основному функционалу – устанавливать время. Экран нужен лишь для отображения этапов процесса и, по окончании процесса установки времени, отображения свежеустановленных времени, даты и дня недели. Причём данные к тому времени будут уже считываться из самого модуля часов. В «урезанной» версии роль экрана выполняет встроенный в плату Arduino светодиод: по окончании процесса установки нового времени он начнет светиться. Вот и вся индикация.

Для чего же кнопка ресет? Для того, что в полной версии после установки времени Arduino войдёт в бесконечный цикл по отображению того самого свежеустановленного времени, то есть, по сути, станет часами. Причём часами, сделанными на скорую руку, в связи с чем они не смогут заменить нормальные часы в силу нескольких причин (выборка секунд реализована через delay, пропадёт отображение времени при отключении питания). Ведь цель – убедиться, что время синхронизировано верно, не более того. Следовательно, для синхронизации следующего модуля часов без ресета не обойтись (точнее, можно обойтись, если «передёрнуть» USB кабель). Другими словами, назначение кнопки – сугубо утилитарное. При желании, можно обойтись и без неё.

Как же прошивать Arduino, ведь версии «железа» две, а скетч один? Для компиляции «правильной» версии прошивки в заголовке скетча нужно установить желаемое значение параметра fullVersion: true для «полной» версии, или false - для «урезанной». Компилятор таким образом определит, для какой версии «железа» компилировать прошивку.

Итак, схема подключения есть, нужен код скетча. Обратите внимание, что для нормальной работы скетча с «полной» версией нужна библиотека LiquidCrystal I2C by Frank de Brabander (устанавливается из репозитория при помощи Менеджера Библиотек). Также нужна библиотека для поддержки модуля часов, причём не любая:). Качать здесь: . С библиотеками разобрались.

Вот код скетча:

//======================================== настройка, доступная для изменения ======================================== #define fullVersion true //true = "полная" версия с экраном; false = "урезанная" версия со встроенным светодиодом //================================= используемые библиотеки и объявление переменных ================================== #include #include #if (fullVersion) #include #endif unsigned long t1 = 0; //переменная для полученного времени unsigned long t2 = 0; //переменная для полученного времени byte b; //буфер для получения данных из COM порта #if (fullVersion) byte day = 0; #endif DS3231 clock; RTCDateTime dat1; #if (fullVersion) LiquidCrystal_I2C lcd(0x3F,16,2); //китайси полюбили новый адрес для "переходников" с i2c в экран #endif //==================================================================================================================== void setup(){ #if (!fullVersion) //актуально только для "урезанной" версии - начало участка кода pinMode(13, OUTPUT); digitalWrite(13,LOW); #endif //актуально только для "урезанной" версии - конец участка кода clock.begin(); Serial.begin(9600); #if (fullVersion) //актуально только для "полной" версии - начало участка кода lcd.init(); lcd.backlight(); lcd.setCursor(0,0); lcd.print("COMport 9600 8N1"); //подсказка, какие параметры COM порта выбирать в программе lcd.setCursor(0,1); lcd.print("Ready to sync"); //сообщение статуса - готовы к синхронизации delay(1000); #endif //актуально только для "полной" версии - конец участка кода } void loop(){ if (Serial.available()){ //если есть "порох в пороховницах" COM порта Serial.readBytes(b,4); //считаем все 4 байта (другого мы и не ждём) t1=b; t2=(t1<<24); //поместить значение байта в 4-байтную переменную и передвинуть его на 3 байта влево t1=b; t2+=(t1<<16); //поместить значение байта в 4-байтную переменную и передвинуть его на 2 байта влево t1=b; t2+=(t1<<8); //поместить значение байта в 4-байтную переменную и передвинуть его на 1 байт влево t2+=b; //поместить значение байта в 4-байтную переменную clock.setDateTime(t2); //установить полученное время на DS3231 #if (fullVersion) //актуально только для "полной" версии - начало участка кода lcd.clear(); lcd.setCursor(0,0); lcd.print("Done:) : :"); while (true){ //начало бесконечного цикла по отображению свежеустановленных времени и даты dat1 = clock.getDateTime(); if (dat1.day != day){ day = dat1.day; lcd.setCursor(0,1); if (dat1.day < 10) lcd.print("0"); lcd.print(day); lcd.print("-"); switch (dat1.month){ //выбираем буквенное соответствие месяца по цифре case 1:{ lcd.print("Jan"); break; } case 2:{ lcd.print("Feb"); break; } case 3:{ lcd.print("Mar"); break; } case 4:{ lcd.print("Apr"); break; } case 5:{ lcd.print("May"); break; } case 6:{ lcd.print("Jun"); break; } case 7:{ lcd.print("Jul"); break; } case 8:{ lcd.print("Aug"); break; } case 9:{ lcd.print("Sep"); break; } case 10:{ lcd.print("Oct"); break; } case 11:{ lcd.print("Nov"); break; } case 12:{ lcd.print("Dec"); break; } default:{ lcd.print("???"); break; } }//switch month lcd.print("-"); lcd.print(dat1.year); lcd.print(" "); switch(dat1.dayOfWeek){ //выбираем буквенное соответствие дня недели по цифре case 1:{ lcd.print("Mon"); break; } case 2:{ lcd.print("Tue"); break; } case 3:{ lcd.print("Wed"); break; } case 4:{ lcd.print("Thu"); break; } case 5:{ lcd.print("Fri"); break; } case 6:{ lcd.print("Sat"); break; } case 7:{ lcd.print("Sun"); break; } default:{ lcd.print("???"); break; } }//switch dayOfWeek }//if date changed lcd.setCursor(8,0); if (dat1.hour < 10) lcd.print("0"); lcd.print(dat1.hour); lcd.setCursor(11,0); if (dat1.minute < 10) lcd.print("0"); lcd.print(dat1.minute); lcd.setCursor(14,0); if (dat1.second < 10) lcd.print("0"); lcd.print(dat1.second); delay(995); }//while #else //актуально только для "урезанной" версии - начало участка кода digitalWrite(13, HIGH); delay(3000); digitalWrite(13, LOW); #endif //актуально только для "полной" версии - конец участка кода }//if Serial }//loop


Пара фото «полной» версии готового девайса.


Ну и, наконец, видео работы девайса «в бою»:

Где скачать скетч и программу?

Скетч качать (Dropbox).
Программу для Windows качать (Dropbox).

«Плюсы» и «минусы».

Сформулировать «плюсы» и «минусы» в данном случае тяжело. Следовательно, каждый решает для себя сам, что – хорошо, а что – плохо.

Итого.

Мне очень понравилось, как теперь устанавливается время в модулях! При необходимости установить время мне не приходится вспоминать каждый раз, какой же там скетч мне нужен и задумываться, насколько точно будет установлено время в модуле. Более того, скоро будет обзор самодельных часов, куда я встроил такой метод синхронизации – настолько метод мне понравился. Надеюсь, кому-то из читателей метод также придётся кстати.

Проект - свободный, некоммерческий. Каждый вправе использовать данные из обзора в любых целях, кроме коммерческих.

Всем добра.

Планирую купить +48 Добавить в избранное Обзор понравился +60 +114

Многие устройства требуют постоянного учёта хронометрических данных (дата, время), эту функцию выполняют специальные электронные схемы, которые называются часами реального времени. Часы реального времени, в нынешнее время, реализованы в виде отдельной микросхемы, к которой нужно добавить кварцевый резонатор и автономный источник питания. В некоторых микросхемах, кварцевый резонатор встроен внутри. Одни из таких часов на микросхеме DS3231SN я купил для своих проектов . В примере буду подключать часы реального времени к китайскому аналогу Arduino UNO.

Представляют из себя законченный модуль ZS-042, который можно подключать к различным устройствам, не только к платформе Arduino.


Модуль построен на микросхеме DS3231SN , которая по сути и является часами реального времени. В отличии от старой модели часов, например на микросхеме DS1307, эти часы содержат внутренний кварцевый резонатор, благодаря чему часы имеют точный ход.

Реализовать часы на Arduino можно и без DS3231SN , но тогда при пропадании питания, значения таймера сбрасываются. Эти же часы имеют резервное питание, поэтому при пропадании питания, они продолжают дальше работать.

Часы умеют производить подсчёт часов, минут, секунд, дат, месяцев, лет (високосные года учитываются до 2100 года). Работают в 12 или 24 часовом режиме, содержат два будильника, а так же имеют внутренний термометр, с диапазоном от -40 ° C до + 85 ° C. Для подключения к различным устройствам, часы подключаются по I2C интерфейсу.


Расположение и назначение пинов на модуле ZS-042:

SQW - Программируемый выход Square-Wave сигнала.

SCL Через этот пин по интерфейсу I2C происходит обмен данными с часами.

SDA Через этот пин передаются данные с часов.

VCC Питание часов реального времени, нужно 5 вольт. Если на этот пин не поступает напряжение, часы переходят в спящий режим.

GND - Земля.

Для подключения к Arduino UNO, пин SDA часов подключаем к пину A4, а пин SCL к A5. Для питания используются пины GND(-) и VCC(+5v).

Пины SDA и SCL на разных платах Arduino:

SDA SCL
UNO A4 A5
Mini A4 A5
Nano A4 A5
Mega2560 20 21
Leonardo 2 3

Установим батарейку CR2032 в часы, такие элементы используются для питания BIOS в компьютерах.

При подключении USB кабеля к Arduino, на часах должен загореться светодиод «POWER » (красный светодиод).

Для того что бы запрограммировать часы через Arduino IDE нужно установить библиотеки.

Скачать библиотеку Time и DS1307RTC .

Последняя библиотека была написана для часов на микросхеме DS1307, но её протоколы взаимодействия совместимы с DS3231, поэтому библиотека подойдёт к нашим часам.

Библиотеки нужно скачать, распаковать и поместить в папку « libraries ». При запуске Arduino IDE, они с примерами должны появится в «Образцах ».

Устанавливаем Дату и время.

Для этого скопируем данный код в Arduino IDE.

Для корректной настройки нужно изменить данные в строке

setTime(13,35,0,22,12,2016);



В скобках через запятую устанавливаем правильные: часы, минуты, секунды, число, месяц, год. У меня в примере установлено 13 часов 35 минут 0 секунд, 22 декабря 2016 год. Вгружаем скетч в Arduino.

Теперь для того что бы прочитат ь показания из часов, можно воспользоваться примером: «Файл » - «Образцы » - «DS1307RTC » - «ReadTest » и за грузить его в Arduino.

В открывшемся окне будет отображаться текущие дата и время. Если отключить питание модуля часов от Arduino, Arduino не сможет отслеживать значения и в мониторе через какое то время появится надпись "...read error! " (выделил красным). После возобновления питания, показания даты и времени будут отсчитываться далее. Показания даты и времени не сбросились, поскольку часы питались от своей батарейки CR2032.

 

 

Это интересно: