Подключение модуля часов реального времени DS1307 к Arduino

Подключение модуля часов реального времени DS1307 к Arduino

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

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

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

Давайте начнём и дадим вашему Arduino возможность отслеживать время как профессионал!

Обзор оборудования

Чип RTC DS1307

В центре этого модуля находится DS1307 — недорогой, высокоточный чип часов реального времени (RTC) на базе I2C, произведённый компанией Maxim Integrated.

Interface DS1307 RTC Module with Arduino

DS1307 может отслеживать секунды, минуты, часы, дни, даты, месяцы и годы. Он достаточно умён, чтобы знать, сколько дней в каждом месяце, и автоматически корректируется для месяцев с числом дней менее 31. Он также правильно обрабатывает високосные годы — правда, только до 2100 года.

Вы можете настроить время в формате 12 часов (с AM и PM) или 24 часов, в зависимости от ваших предпочтений.

На чипе также есть специальный вывод SQW (сокращение от square wave — прямоугольная волна). Вы можете настроить этот вывод на генерацию стабильного импульсного сигнала на одной из четырёх частот: 1 Гц, 4 кГц, 8 кГц или 32 кГц. Это может быть полезно в проектах, которым нужен регулярный тактовый сигнал.

DS1307 использует внешний кварцевый резонатор на 32 кГц для отслеживания времени. Именно этот кварц помогает чипу отмерять каждую проходящую секунду. Однако есть небольшая проблема: частота кварца может немного меняться при изменении температуры окружающей среды.

Хотя изменение очень незначительное, со временем оно может привести к тому, что часы постепенно станут менее точными. Фактически время может уходить примерно на пять минут в месяц.

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

Резервное питание от батареи

Чип DS1307 включает функцию резервного питания от батареи, которая помогает поддерживать работу часов даже при отключении основного питания.

На задней стороне модуля есть держатель батареи, предназначенный для литиевой батарейки-таблетки диаметром 20 мм на 3 В.

Interface DS1307 RTC Module with Arduino

Внутри чипа есть встроенная интеллектуальная схема контроля питания, которая постоянно проверяет, включено ли основное питание. Если эта схема обнаруживает, что основное питание потеряно, она автоматически переключается на резервную батарею.

Встроенный EEPROM 24C32

Помимо чипа DS1307, модуль также содержит EEPROM 24C32. EEPROM расшифровывается как Electrically Erasable Programmable Read-Only Memory (электрически стираемая программируемая постоянная память). Этот чип не используется для хронометрирования, но он отлично подходит для сохранения данных — таких как журналы, показания датчиков или настройки — которые вы хотите сохранить даже после выключения питания.

Interface DS1307 RTC Module with Arduino

EEPROM 24C32 может хранить до 32 килобит данных. Он рассчитан примерно на 1 000 000 циклов записи, что означает, что вы можете сохранять данные множество раз, прежде чем он износится.

Этот чип EEPROM использует тот же протокол связи I2C, как и DS1307, и оба чипа разделяют одну шину I2C.

Интерфейс I2C

Модуль DS1307 использует протокол I2C для связи с микроконтроллерами, такими как Arduino или Raspberry Pi. При подключении модуля к вашему проекту он использует два различных I2C-адреса:

  • Чип RTC DS1307 имеет фиксированный I2C-адрес 0x68.

  • Чип EEPROM имеет фиксированный I2C-адрес 0x50.

Подключения I2C — SDA (данные) и SCL (тактирование) — вместе с питанием (VCC) и землёй (GND) выведены на обеих сторонах платы. Это упрощает подключение модуля к вашему проекту или даже последовательное соединение с другими I2C-устройствами.

Interface DS1307 RTC Module with Arduino

Скрытая функция модуля — поддержка DS18B20:

Интересная скрытая функция модуля RTC DS1307 заключается в том, что на нём есть место для установки датчика температуры DS18B20, которое многие люди даже не замечают.

Вы можете установить DS18B20, используя три монтажных отверстия в правом верхнем углу платы, рядом с держателем батареи (обозначены U1).

Interface DS1307 RTC Module with Arduino

После установки вы можете считывать данные о температуре с вывода DS. Эти показания температуры можно использовать для коррекции дрейфа времени, вызванного изменениями температуры.

Технические характеристики

Вот технические характеристики:

Рабочее напряжение

4.5 to 5.5V (5V typical)

Потребляемый ток

< 1.5mA (typ.)

Точность (0-40°C)

Зависит от кварца (± 20ppm typ.)

Батарея

CR2032 (3V Coin)

Для получения дополнительной информации о DS1307 RTC и чипе EEPROM 24C32 обратитесь к техническим описаниям, перечисленным ниже.

Распиновка модуля RTC DS1307

Модуль RTC DS1307 имеет всего 7 выводов. Вот что делает каждый вывод:

Interface DS1307 RTC Module with Arduino

SQW — выходной вывод прямоугольной волны. Этот вывод может быть настроен на генерацию сигнала прямоугольной волны на различных выбираемых частотах: 1 Гц, 4 кГц, 8 кГц или 32 кГц. Этот сигнал может быть полезен в проектах, которым нужен стабильный тактовый импульс.

DS — дополнительный вывод. Он выдаёт показания температуры, если установлен датчик температуры DS18B20 через три монтажных отверстия в правом верхнем углу модуля (обозначены U1).

SCL — вывод тактирования для I2C-связи.

SDA — вывод данных для I2C-связи.

VCC — вывод питания. Должен быть подключён к выводу 5V на Arduino.

GND — это вывод заземления.

BAT — предназначен для подключения резервной батареи 3 В, обычно батарейки-таблетки CR2032. Батарея питает DS1307, когда основное питание (VCC) выключено или недоступно.

Схема подключения модуля RTC DS1307 к Arduino

Давайте подключим модуль DS1307 к Arduino! Процесс подключения прост и требует всего нескольких шагов.

Сначала подключите вывод VCC на модуле к выходу 5V на Arduino, а вывод GND — к земле Arduino.

Далее нам нужно подключить выводы для I2C-связи. Важно знать, что разные платы Arduino имеют разные выводы I2C, и их необходимо подключать правильно. На платах Arduino с компоновкой R3 выводы SDA и SCL также расположены на штыревых разъёмах рядом с выводом AREF. Однако внутренне они являются теми же выводами A4 (SDA) и A5 (SCL).

Вот краткая справочная таблица подключений:

DS1307 ModuleArduino
VCC5V
GNDGND
SCLSCL or A5
SDASDA or A4

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

Interface DS1307 RTC Module with Arduino

Установка библиотеки

Для использования модуля DS1307 в наших проектах мы воспользуемся специальной библиотекой `uRTCLib `_. Эта библиотека делает считывание данных времени с RTC очень простым.

Несмотря на простоту использования, uRTCLib также очень мощная. В отличие от многих других RTC-библиотек, она поддерживает будильники по времени суток и позволяет управлять выходом SQW (прямоугольная волна).

Для установки библиотеки:

  1. Сначала откройте вашу программу Arduino IDE. Затем нажмите на значок Менеджер библиотек на левой боковой панели.

  2. Введите «urtclib» в поле поиска для фильтрации результатов.

  3. Найдите uRTCLib Library от Naguissa.

  4. Нажмите кнопку Install, чтобы добавить её в вашу Arduino IDE.

Interface DS1307 RTC Module with Arduino

Далее в руководстве мы также покажем, как читать и записывать данные во встроенный чип EEPROM 24C32. Если вам интересно это попробовать, вам также потребуется установить другую библиотеку — uEEPROMLib.

Для её установки: просто найдите «uEEPROMLib» в менеджере библиотек таким же образом и нажмите Install.

Interface DS1307 RTC Module with Arduino

Код Arduino — Считывание даты и времени

В этом примере мы используем простой скетч Arduino для установки и считывания даты, времени и температуры с модуля RTC DS1307.

#include "Arduino.h"
#include "uRTCLib.h"

// uRTCLib rtc;
uRTCLib rtc(0x68);

char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

void setup() {
  Serial.begin(9600);

  URTCLIB_WIRE.begin();

  // Comment out below line once you set the date & time.
  // Following line sets the RTC with an explicit date & time
  // for example to set April 14 2025 at 12:56 you would call:
  rtc.set(0, 56, 12, 2, 14, 4, 25);
  // rtc.set(second, minute, hour, dayOfWeek, dayOfMonth, month, year)
  // set day of week (1=Sunday, 7=Saturday)
}

void loop() {
  rtc.refresh();

  Serial.print("Current Date & Time: ");
  Serial.print(rtc.year());
  Serial.print('/');
  Serial.print(rtc.month());
  Serial.print('/');
  Serial.print(rtc.day());

  Serial.print(" (");
  Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
  Serial.print(") ");

  Serial.print(rtc.hour());
  Serial.print(':');
  Serial.print(rtc.minute());
  Serial.print(':');
  Serial.println(rtc.second());

  delay(1000);
}

После загрузки кода на Arduino откройте монитор последовательного порта и установите скорость передачи данных на 9600 бод. Вы увидите текущую дату и время в удобном формате.

Interface DS1307 RTC Module with Arduino

Объяснение кода:

Мы начинаем с подключения двух важных библиотек: Arduino.h и uRTCLib.h. Они помогают Arduino взаимодействовать с чипом DS1307.

#include "Arduino.h"
#include "uRTCLib.h"

Далее мы создаём объект RTC с помощью библиотеки uRTCLib и определяем массив daysOfTheWeek, который содержит названия дней недели от воскресенья до субботы.

// uRTCLib rtc;
uRTCLib rtc(0x68);

char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };

В функции setup() мы открываем монитор последовательного порта, чтобы выводить показания даты, времени и температуры на экран. Затем мы используем функцию URTCLIB_WIRE.begin() для запуска I2C-связи.

URTCLIB_WIRE.begin();

Затем мы устанавливаем дату и время вручную с помощью функции rtc.set(). Вам нужно запустить это только один раз для установки правильной даты и времени. После этого вы должны закомментировать эту строку, чтобы она не сбрасывалась каждый раз при загрузке кода.

Например, строка rtc.set(0, 56, 12, 2, 14, 4, 25); устанавливает время на 12:56 в понедельник, 14 апреля 2025 года. Значения представляют: секунды, минуты, часы, день недели (1 = воскресенье), день месяца, месяц и последние две цифры года.

rtc.set(0, 56, 12, 2, 14, 4, 25);

В функции loop() мы вызываем функцию rtc.refresh() для обновления значений даты и времени с чипа.

rtc.refresh();

Затем мы выводим текущий год, месяц и день в монитор последовательного порта. Мы также используем значение dayOfWeek() в качестве индекса для вывода названия дня из нашего массива daysOfTheWeek.

Serial.print("Current Date & Time: ");
Serial.print(rtc.year());
Serial.print('/');
Serial.print(rtc.month());
Serial.print('/');
Serial.print(rtc.day());

Serial.print(" (");
Serial.print(daysOfTheWeek[rtc.dayOfWeek() - 1]);
Serial.print(") ");

После этого мы выводим часы, минуты и секунды для отображения текущего времени.

Serial.print(rtc.hour());
Serial.print(':');
Serial.print(rtc.minute());
Serial.print(':');
Serial.println(rtc.second());

В конце цикла мы добавляем задержку в 1 секунду, чтобы данные обновлялись раз в секунду.

Код Arduino — Чтение и запись в EEPROM 24C32

Как вы уже знаете, модуль RTC DS1307 поставляется со встроенным чипом EEPROM 24C32, который предоставляет 32 килобита памяти. Этого достаточно для хранения небольших фрагментов данных, таких как настройки, пароли, журналы датчиков или что-либо ещё, что вы хотите сохранить.

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

#include "Arduino.h"
#include "Wire.h"
#include "uEEPROMLib.h"

// uEEPROMLib eeprom;
uEEPROMLib eeprom(0x50);

void setup() {
  Serial.begin(9600);

  Wire.begin();

  int inttmp = 32123;
  float floattmp = 3.1416;
  char chartmp = 'A';
  char c_string[] = "lastminuteengineers.com";  // 23 Characters
  int string_length = strlen(c_string);

  Serial.println("Writing into memory...");

  // Write an int
  if (!eeprom.eeprom_write(0, inttmp)) {
    Serial.println("Failed to store int.");
  } else {
    Serial.println("int was stored correctly.");
  }

  // write a float
  if (!eeprom.eeprom_write(4, floattmp)) {
    Serial.println("Failed to store float.");
  } else {
    Serial.println("float was stored correctly.");
  }

  // Write single char at address
  if (!eeprom.eeprom_write(8, chartmp)) {
    Serial.println("Failed to store char.");
  } else {
    Serial.println("char was stored correctly.");
  }

  // Write a long string of chars FROM position 33 which isn't aligned to the 32 byte pages of the EEPROM
  if (!eeprom.eeprom_write(33, (byte *)c_string, strlen(c_string))) {
    Serial.println("Failed to store string.");
  } else {
    Serial.println("string was stored correctly.");
  }

  Serial.println("");
  Serial.println("Reading memory...");

  Serial.print("int: ");
  eeprom.eeprom_read(0, &inttmp);
  Serial.println(inttmp);

  Serial.print("float: ");
  eeprom.eeprom_read(4, &floattmp);
  Serial.println((float)floattmp);

  Serial.print("char: ");
  eeprom.eeprom_read(8, &chartmp);
  Serial.println(chartmp);

  Serial.print("string: ");
  eeprom.eeprom_read(33, (byte *)c_string, string_length);
  Serial.println(c_string);

  Serial.println();
}

void loop() {
}

После загрузки кода на Arduino откройте монитор последовательного порта и установите скорость передачи данных на 9600 бод. Вывод в мониторе последовательного порта покажет записанные нами значения, доказывая, что EEPROM надёжно хранит данные.

Interface DS1307 RTC Module with Arduino

Объяснение кода:

Мы начинаем с подключения библиотек Arduino.h, Wire.h и uEEPROMLib.h. Эти библиотеки позволяют Arduino взаимодействовать с EEPROM по I2C.

#include "Arduino.h"
#include "Wire.h"
#include "uEEPROMLib.h"

Далее мы создаём объект EEPROM с I2C-адресом по умолчанию 0x50.

uEEPROMLib eeprom(0x50);

В функции setup() мы инициализируем монитор последовательного порта, чтобы видеть результаты, и начинаем I2C-соединение с помощью Wire.begin().

Wire.begin();

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

int inttmp = 32123;
float floattmp = 3.1416;
char chartmp = 'A';
char c_string[] = "lastminuteengineers.com";  //23 Characters
int string_length = strlen(c_string);

Для записи данных в EEPROM мы используем функцию eeprom_write(). Мы передаём ей адрес памяти и значение, которое хотим сохранить. Каждый раз при записи мы проверяем, была ли она успешной, и выводим сообщение для подтверждения.

Мы сохраняем целое число по адресу 0, число с плавающей точкой по адресу 4, символ по адресу 8 и строку, начиная с адреса 33. Причина, по которой мы начинаем строку с более высокого адреса, — избежать перекрытия с другими данными, уже сохранёнными в нижних адресах памяти.

// Write an int
if (!eeprom.eeprom_write(0, inttmp)) {
  Serial.println("Failed to store int.");
} else {
  Serial.println("int was stored correctly.");
}

// write a float
if (!eeprom.eeprom_write(4, floattmp)) {
  Serial.println("Failed to store float.");
} else {
  Serial.println("float was stored correctly.");
}

// Write single char at address
if (!eeprom.eeprom_write(8, chartmp)) {
  Serial.println("Failed to store char.");
} else {
  Serial.println("char was stored correctly.");
}

// Write a long string of chars FROM position 33 which isn't aligned to the 32 byte pages of the EEPROM
if (!eeprom.eeprom_write(33, (byte *)c_string, strlen(c_string))) {
  Serial.println("Failed to store string.");
} else {
  Serial.println("string was stored correctly.");
}

После записи мы переходим к чтению данных обратно с помощью функции eeprom_read(). Мы выводим значения одно за другим, чтобы убедиться, что всё было сохранено правильно.

Serial.print("int: ");
eeprom.eeprom_read(0, &inttmp);
Serial.println(inttmp);

Serial.print("float: ");
eeprom.eeprom_read(4, &floattmp);
Serial.println((float)floattmp);

Serial.print("char: ");
eeprom.eeprom_read(8, &chartmp);
Serial.println(chartmp);

Serial.print("string: ");
eeprom.eeprom_read(33, (byte *)c_string, string_length);
Serial.println(c_string);

Примечание:

При записи в EEPROM важно понимать, сколько места занимают различные типы данных:

Это означает, что нужно быть внимательным с тем, где вы храните каждый тип данных. Например, если вы сохранили целое число по адресу 0, вы не должны сохранять что-либо ещё по адресу 1, потому что целые числа занимают два байта. Вместо этого следующее значение следует хранить по адресу 2 или выше. Таким образом, для хранения нескольких целых чисел вы бы использовали адреса памяти 0, 2, 4, 6 и так далее.

Это помогает предотвратить перекрытие или повреждение данных.