ESP-IDF: драйвер микросхем RTC DS337 и DS3231 Печать
Добавил(а) microsin   

Для работы микросхемой часов реального времени DS337 и DS3231/DS3231M (RTC) существует внешний компонент [1, 2].

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

DS3231 I2C connect

Рис. 1. Подключение модуля DS3231 к плате ESP32.

Для работы с компонентом необходима установленная среда ESP-IDF версии v5.0+. Для начала работы с компонентом в каталоге проекта запустите команду:

$ idf.py add-dependency "jschwefel/esp-idf-ds3231^1.0.0"

Чтобы использовать функции библиотеки, добавьте в код подключение заголовка esp-idf-ds3231.h:

#include "esp-idf-ds3231.h"

Простой пример использования:

#include < stdio.h>
#include "esp-idf-ds3231.h"

void app_main(void) { // Выделение памяти для указателя на дескриптор i2c_master_bus_handle_t: i2c_master_bus_handle_t* bus_handle = (i2c_master_bus_handle_t*)malloc(sizeof(i2c_master_bus_handle_t)); // Создание структуры конфигурации i2c_master_bus_config_t и присвоение её значений: i2c_master_bus_config_t i2c_mst_config = { .clk_source = I2C_CLK_SRC_DEFAULT, .i2c_port = -1, .scl_io_num = GPIO_NUM_5, .sda_io_num = GPIO_NUM_4, .glitch_ignore_cnt = 7, // Микросхема DS3231 **требует** наличия внешних pullup-резисторов на всех её выводах I/O. // Замечание: на многих платах DS3231 уже есть эти резисторы. .flags.enable_internal_pullup = true, }; i2c_new_master_bus(&i2c_mst_config, bus_handle); rtc_handle_t* rtc_handle = ds3231_init(bus_handle);
time_t now; char strftime_buf[64]; struct tm timeinfo; now = ds3231_time_unix_get(rtc_handle); localtime_r(&now, &timeinfo); strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); printf("Текущее время, прочитанное из DS3231 RTC: %s\n", strftime_buf); }

В следующей таблице приведено краткое описание функций библиотеки. Полное описание функций есть заголовочном файле esp-idf-ds3231.h (также см. врезку далее).

Функция Описание
ds3231_init_full Инициализирует I2C и модуль DS3231 RTC.
ds3231_init Инициализация модуля DS3231 RTC с предварительно созданным дескриптором шины.
ds3231_debug_print_data Функция для тестирования. Она прочитает все регистры и напечатает их данные.
ds3231_get_registers_raw Запрашивает у DS3231 содержимое всех регистров (00h - 12h) в виде сырых данных.
ds3231_send_byte_raw Посылает одиночный байт в указанный регистр DS3231.
ds3231_time_minutes_or_seconds_get Запрашивает у DS3231 содержимое регистров минут или секунд. Работает как с регистрами Time, так и с регистрами Alarm.
ds3231_time_hours_get Запрашивает у DS3231 содержимое регистра часа. Работает как с регистрами Time, так и с регистрами Alarm.
ds3231_time_day_of_week_get Запрашивает у DS3231 содержимое регистра дня недели. Работает как с регистрами Time, так и с регистрами Alarm.
ds3231_time_date_get Запрашивает у DS3231 содержимое дня месяца. Работает как с регистрами Time, так и с регистрами Alarm.
ds3231_time_month_get Запрашивает у DS3231 содержимое регистра месяца. Работает только на Time.
ds3231_time_year_get Запрашивает у DS3231 содержимое регистра года. Работает только на Time.
ds3231_aging_offset_get Запрашивает у DS3231 содержимое регистра смещения старения (Aging Offset).
ds3231_temperature_get Запрашивает у DS3231 содержимое регистра температуры.
ds3231_control_status_flags_get Запрашивает у DS3231 содержимое регистров управления (Control) и состояния (Status).
ds3231_time_get Запрашивает у DS3231 текущее значение времени, возвращенное как struct tm.
ds3231_time_time_t_set Установит время DS3231, используя значение time_t.
ds3231_time_unix_get Запрашивает у DS3231 значение текущего времени, возвращаемое как struct tm.
ds3231_time_unix_set Установит время DS3231, используя значение времени Unix.
ds3231_time_tm_set Установит время DS3231, используя значение struct tm.
ds3231_alarm_isr_create Создаст прерывание по сигналу на выводе порта (GPIO Pin interrupt) и соответствующую очередь обработки, а также назначит определяемую пользователем функцию для обработки прерываний, генерируемых сигналом на выводе INT DS3231.
ds3231_alarm_isr_delete Удаляет alarm isr, ранее созданный вызовом ds3231_alarm_isr_create.
ds3231_alarm1_time_get Запрашивает у DS3231 установку значения Alarm 1.
ds3231_alarm1_day_of_week_set Установит значение Alarm 1 для срабатывания на одном и том же дне каждой недели.
ds3231_alarm1_day_of_month_set Установит значение Alarm 1 для срабатывания на одном и том же дне каждого месяца.
ds3231_alarm1_enable_flag_get Возвратит двоичное значение, представляющее статус разрешения Alarm 1.
ds3231_alarm1_enable_flag_set Установит состояние разрешено/запрещено для Alarm 1.
ds3231_alarm1_fired_flag_get Получит статус срабатывания Alarm 1.
ds3231_alarm1_rate_get Получит условия срабатывания Alarm 1, как это описано в rtc_alarm_rate_e.
ds3231_alarm1_rate_set Установит условие срабатывания Alarm 1, как это описано в rtc_alarm_rate_e.
ds3231_alarm1_fired_flag_reset Сбросит в 0 флаг срабатывания Alarm 1.
ds3231_alarm2_time_get Запросит у DS3231 установленное значение Alarm 2.
ds3231_alarm2_day_of_week_set Установит значение Alarm 2, чтобы он срабатывал в один и тот же день недели.
ds3231_alarm2_day_of_month_set Установит значение Alarm 2, чтобы он срабатывал в один и тот же день каждого месяца.
ds3231_alarm2_enable_flag_get Вернет двоичное значение, представляющее состояние разрешен/запрещен будильника Alarm 2.
ds3231_alarm2_enable_flag_set Установит состояние разрешен/запрещен будильника Alarm 2.
ds3231_alarm2_fired_flag_get Получит статус флага срабатывания Alarm 2.
ds3231_alarm2_rate_set Установит условие срабатывания Alarm 2, как это описано rtc_alarm_rate_e.
ds3231_alarm2_fired_flag_reset Сбросит в 0 флаг срабатывания Alarm 2.
ds3231_set_esp_with_rtc Синхронизирует время ESP32 с временем из DS3231.
ds3231_enable_oscillator_flag_get Получит статус флага генератора (Oscillator Flag).
ds3231_enable_oscillator_flag_set Установит статус флага генератора (Oscillator Flag).
ds3231_battery_backed_square_wave_flag_get Получит статус флага генерации выходного прямоугольного сигнала при работе от батареи (Battery Backed Square Wave Flag).
ds3231_battery_backed_square_wave_flag_set Установит состояние Battery Backed Square Wave Flag.
ds3231_convert_temp_flag_get Вернет состояние флага преобразования температуры (Convert Temp Temperature Flag).
ds3231_convert_temp_flag_set Установит состояние Convert Temperature Flag.
ds3231_square_wave_freq_get Получит текущее значение (1 .. 4) настройки выхода генерации прямоугольника.
ds3231_square_wave_freq_set Установит значение перечисления (1 .. 4) для настройки генерируемого прямоугольного сигнала.
ds3231_interrupt_square_wave_control_flag_get Получит статус Interrupt/Square Wave Flag.
ds3231_interrupt_square_wave_control_flag_set Установит значение флага управления формированием прямоугольника.
ds3231_get_oscillator_stop_flag Получит состояние флага остановки генератора (Oscillator Stop Flag).
ds3231_oscillator_stop_flag_reset Сбросит состояние Oscillator Stop Flag.
ds3231_32kHz_out_enable_flag_get Получит состояние флага генерации 32 кГц.
ds3231_32kHz_out_enable_flag_set Установит состояние флага генерации 32 кГц.
ds3231_busy_flag_get Получит состояние флага занятости (Busy Flag).
ds3231_register_set Подобная концепция в ds3231_set_registers_raw. Позволяет установить один регистр одним байтом данных.
ds3231_set_registers_raw Подобная концепция в ds3231_register_set. Позволяет установить несколько идущих друг за другом регистров из массива данных.
ds3231_debug_print_data Получит все регистры времени, будильника и управления/статуса. Данные выводятся функцией ESP_LOGI.
ds3231_debug_test_set Получит и установит/сбросит все флаги из регистров управления/статуса. Данные выводятся функцией ESP_LOGI.

/*
 * esp-idf-ds3231 component library for the ESP32 family of microcontrollers
 * using ESP-IDF v5.0 or later.
 * Copyright 224 Jason M. Schwefel
 *
 * Licensed under the MIT License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/license/MIT
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once
#include < sys/time.h>
#include "driver/gpio.h"
#include "driver/i2c_master.h"

#ifdef __cplusplus
extern "C" {
#endif

#define RTC_I2C_TIMEOUT \ 1000 /*!< @brief Таймаут команд I2C в мс, по умолчанию 1000. Переопределите при необходимости. \ Для отключения таймаута используйте -1 \ */

/** * @brief Перечисление для всех значений регистров DS3231 RTC * */
enum rtc_register_e { RTC_REGISTER_TIME_SECONDS = 0x00, /*!< Time - регистр секунд */ RTC_REGISTER_TIME_MINUTES = 0x01, /*!< Time - регистр минут */ RTC_REGISTER_TIME_HOURS = 0x02, /*!< Time - регистр часов */ RTC_REGISTER_TIME_DAY = 0x03, /*!< Time - регистр дня недели (Day of Week) */ RTC_REGISTER_TIME_DATE = 0x04, /*!< Time - регистр дня месяца (Day of Month) */ RTC_REGISTER_TIME_MONTH = 0x05, /*!< Time - регистр месяца */ RTC_REGISTER_TIME_YEAR = 0x06, /*!< Time - регистр года */ RTC_REGISTER_ALARM1_SECONDS = 0x07, /*!< Alarm 1 - будильник 1, регистр секунд */ RTC_REGISTER_ALARM1_MINUTES = 0x08, /*!< Alarm 1 - будильник 1, регистр минут */ RTC_REGISTER_ALARM1_HOURS = 0x09, /*!< Alarm 1 - будильник 1, регистр часов */ RTC_REGISTER_ALARM1_DAY_DATE = 0x0A, /*!< Alarm 1 - будильник 1, день даты */ RTC_REGISTER_ALARM2_MINUTES = 0x0B, /*!< Alarm 2 - будильник 2, регистр минут */ RTC_REGISTER_ALARM2_HOURS = 0x0C, /*!< Alarm 2 - будильник 2, регистр часов */ RTC_REGISTER_ALARM2_DAY_DATE = 0x0D, /*!< Alarm 2 - будильник 2, день даты */ RTC_REGISTER_CONTROL = 0x0E, /*!< регистры управления и статуса (Control & Status) */ RTC_REGISTER_CONTROL_UPPER = 0x0E, /*!< верхние регистры управления и статуса (Upper Control & Status) */ RTC_REGISTER_CONTROL_LOWER = 0x0F, /*!< нижние регистры управления и статуса (Lower Control & Status) */ RTC_REGISTER_AGING_OFFSET = 0x10, /*!< регистр учета старения (Aging Offset) */ RTC_REGISTER_TEMPERATURE = 0x11 /*!< регистры температуры */ };

/** * @brief Перечисление для всех дней недели, используемых чипом DS3231. * * @note Значения Day of Week, используемые \b DS3231 и структурой \b struct \b tm, отличаются. * В DS3231 диапазон значений 1 - 7, соответствующих дням от понедельника (Monday) * до воскресенья (Sunday). В структуре tm значения 0 - 6 соответствуют диапазону * дней от воскресенья (Sunday) до субботы (Saturday). Функция ds3231_time_get * учитывает этот факт, а функция ds3231_time_day_of_week_get не учитывает. */
enum rtc_day_of_week_e { RTC_MONDAY = 1, RTC_TUESDAY = 2, RTC_WEDNESDAY = 3, RTC_THURSDAY = 4, RTC_FRIDAY = 5, RTC_SATURDAY = 6, RTC_SUNDAY = 7 };

/** * @brief Перечисление всех значений дней недели, используемых POSIX-структурой time. * * @note The Значения Day of Week, используемые \b DS3231 и структурой \b struct \b tm, отличаются. * В DS3231 диапазон значений 1 - 7, соответствующих дням от понедельника (Monday) * до воскресенья (Sunday). В структуре tm значения 0 - 6 соответствуют диапазону * дней от воскресенья (Sunday) до субботы (Saturday). Функция ds3231_time_get * учитывает этот факт, а функция ds3231_time_day_of_week_get не учитывает. */
enum tm_day_of_week_e { TM_SUNDAY = 0, TM_MONDAY = 1, TM_TUESDAY = 2, TM_WEDNESDAY = 3, TM_THURSDAY = 4, TM_FRIDAY = 5, TM_SATURDAY = 6 };

/** * @brief Перечисление для 4 значений частот, доступных для вывода прямоугольного сигнала на DS3231 */
enum rtc_square_wave_freq_e { RTC_SQUARE_WAVE_FREQ_1000HZ = 0, RTC_SQUARE_WAVE_FREQ_1024HZ = 1, RTC_SQUARE_WAVE_FREQ_4096HZ = 2, RTC_SQUARE_WAVE_FREQ_8192HZ = 3 };

/** * @brief Функционал будильника DS3231, весьма продвинутая. */
enum rtc_alarm_rate_e { RTC_ALARM_MATCH_EVERY_SECOND = 15, /*!< \b Alarm \b 1 \b Only - alarm будет срабатывать каждую секунду. */ RTC_ALARM_MATCH_SECONDS_A1_OR_EVERY_MINUTES_A2 = 14, /*!< \b Alarm \b 1 \b Only - alarm сработает, когда значение секунд в регистре alarm совпадет со значением секунд DS3231. \b Alarm \b 2 \b Only - alarm будет срабатывать каждую минуту, когда значение секунд на DS3231 достигнет 00.*/ RTC_ALARM_MATCH_MINUTES = 12, /*!< alarm будет срабатывать каждый час, когда его минуты (и секунды для Alarm 1) совпадут с минутами DS3231 (и секундами для Alarm 1) */ RTC_ALARM_MATCH_HOURS = 8, /*!< alarm будет срабатывать каждый день, когда его часы, минуты (и секунды Alarm 1) совпадут с часами, минутами DS3231 (и секундами для Alarm 1) */ RTC_ALARM_MATCH_DAY_DATE = 0, /*!< alarm будет срабатывать, когда день, когда часы, минуты (и секунды для Alarm 1) совпадут с днем, часами, минутами DS3231 (и секундами для Alarm 1) */ RTC_ALARM_MATCH_INVALID = -999 /*!< */ };

enum rtc_intr_sqr_e { square = false, interrupts = true };

#pragma pack(push, 1)

/** * @brief Перечисление 2 регистров управления и статуса (0Eh и 0Fh) * DS3231. Все флаги активны, если они равны 1. */
typedef union rtc_control_status_t { uint16_t data; /*!< Традиционное представление данных. */ struct { unsigned alarm1_enable : 1; /*!< Alarm 1 Enable. */ unsigned alarm2_enable : 1; /*!< Alarm 2 Enable. */ unsigned interrupt_control : 1; /*!< Управление прерывание / прямоугольный сигнал (Interrupt/Square Wave Control). Square Wave активно, когда установлено в 1. См. даташит DS3231 для подробностей. */ // clang-format off unsigned square_freq : 2; /*!< Регистр управления частой выходного сигнала (2 бита) | BIT 1 | BIT 0 | OUTPUT FREQ | | :-----: | :-----: | :---------: | | 0 | 0 | 1.000khZ | | 0 | 1 | 1.024KhZ | | 1 | 0 | 4.096KhZ | | 1 | 1 | 8.192KhZ | */ // clang-format on unsigned convert_temp : 1; /*!< Принудительный запуск преобразования температуры. Подробности см. в даташите DS3231 */ unsigned battery_square : 1; /*!< Генерировать прямоугольник при питании от батареи. Подробности см. в даташите DS3231 */ unsigned enable_oscillator : 1; /*!< Active 0 - когда неактивно, все регистры только для чтения */ unsigned alarm1_flag : 1; /*!< Флаг, показывающий срабатывание Alarm 1. Если прерывания разрешены, то будет сформирован сигнал прерывания. */ unsigned alarm2_flag : 1; /*!< Флаг, показывающий срабатывание Alarm 2. Если прерывания разрешены, то будет сформирован сигнал прерывания. */ unsigned busy_flag : 1; /*!< Идет процесс преобразования температуры. */ unsigned enable_32kHz_out : 1; /*!< Разрешает вывод прямоугольного сигнала 32.765kHZ. По умолчанию активно при включенном питании */ /** @cond */ unsigned unused : 3; /** @endcond */ unsigned oscillator_stop_flag : 1; /*!< Показывает, что генератор остановлен. Подробности см. в даташите DS3231 */ }; } rtc_control_status_t;

/** * @brief Простой псевдоним для дескриптора i2c_master_dev_handle. */
typedef i2c_master_dev_handle_t rtc_handle_t;

#pragma pack(pop)

/** * @brief Инициализирует I2C и модуль DS3231 RTC. * @param SCL [in] GPIO_NUM_X ножка для тактов I2C. * @param SDA [in] GPIO_NUM_X ножка для данных I2C. * @retval rtc_handle_t: Дескриптор, необходимый для последующих операций. * @retval NULL: Не получилось создать дескриптор. Проверьте вывод serial monitor для сообщения ошибки. */
rtc_handle_t* ds3231_init_full(gpio_num_t SCL, gpio_num_t SDA);

/** * @brief Инициализация модуля DS3231 RTC с информацией I2C. * @param *bus_handle [in] дескриптор i2c_master_bus_handle_t, ранее созданный вызовом i2c_new_master_bus. * @retval rtc_handle_t: Дескриптор, необходимый для последующих операций. * @retval NULL: Не получилось создать дескриптор. Проверьте вывод serial monitor для сообщения ошибки. */
rtc_handle_t* ds3231_init(i2c_master_bus_handle_t* bus_handle);

/** * @brief Это функция для тестирования. Она прочитает все регистры и напечатает их данные * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. */
void ds3231_debug_print_data(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 содержимое всех регистров (00h - 12h) в виде сырых данных. * @note Возвращенное значение должно быть освобождено вызывающим кодом, чтобы не допустить утечки памяти * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b uint8_t* - массив, содержащий данные всех регистров. */
uint8_t* ds3231_get_registers_raw(rtc_handle_t* rtc_handle);

/** * @brief Посылает одиночный байт в указанный регистр DS3231 * @warning Это потенциально опасная команда. ЛЮБЫЕ данные можно послать в ЛЮБОЙ регистр. * Никакие проверки не выполняются. * @warning Подключение этой функции сделано, чтобы позволить низкоуровневый доступ, который * не предоставляют стандартные функции \a set_x и \a get_x. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] Записываемый регистр. * @param rtc_data [in] Записываемые данные. * @return @b esp_err_t - каскадируется из i2c_master_transmit * - \b ESP_OK: успех I2C master transmit-receive * - \b ESP_ERR_INVALID_ARG: недопустимый параметр I2C master transmit. * - \b ESP_ERR_TIMEOUT: таймаут операции (прошло время, больше чем xfer_timeout_ms) * из-за занятости шины или аппаратной проблемы. */
esp_err_t ds3231_send_byte_raw(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register, uint8_t rtc_data);

/** * @brief Запрашивает у DS3231 содержимое регистров минут или секунд. Работает как с регистрами Time, * так и с регистрами Alarm. * @note У Alarm2 нет регистра секунд. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] rtc_register_e регистр минут/секунд для Time, Alarm 1, Alarm 2 * @return \b uint8_t - один байт, представляющий значение минут или секунд в формате Base-10. * - значения: 0-59 * - формат \b НЕ учитывает високосные секунды (leap seconds) */
int8_t ds3231_time_minutes_or_seconds_get(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register);

/** * @brief Запрашивает у DS3231 содержимое регистра часа. Работает как с регистрами Time, * так и с регистрами Alarm. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] rtc_register_e регистр часов для Time, Alarm 1, Alarm 2 * @return \b uint8_t - один байт, представляющий значение часов, в формате Base-10. * - значения: 0-23. * - данные всегда предоставляются в 24-часовом формате. */
int8_t ds3231_time_hours_get(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register);

/** * @brief Запрашивает у DS3231 содержимое регистра дня недели. Работает как с регистрами Time, * так и с регистрами Alarm. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] rtc_register_e регистр дня недели для Time, Alarm 1, Alarm 2 * @return \b uint8_t - один байт, представляющий день недели (Day of Week). * - значения 1 - 7 * - отсчет дня начинается с понедельника (1 == Monday) */
int8_t ds3231_time_day_of_week_get(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register);

/** * @brief Запрашивает у DS3231 содержимое дня месяца. Работает как с регистрами Time, * так и с регистрами Alarm. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] rtc_register_e регистр дня месяца для Time, Alarm 1, Alarm 2 * @return \b uint8_t - один байт, представляющий день месяца (Day of Month). * - значения 1 - 31 */
int8_t ds3231_time_date_get(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register);

/** * @brief Запрашивает у DS3231 содержимое регистра месяца. Работает только на Time. * @note Neither Регистра месяца нет ни у Alarm 1, ни у Alarm 2. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b uint8_t - один байт, представляющий месяц. * - значения 1 - 12 */
int8_t ds3231_time_month_get(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 содержимое регистра года. Работает только на Time. * @note Neither Регистра года нет ни у Alarm 1, ни у Alarm 2. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b uint16_t - два байта, представляющие год. * - значения 1900 - 2099 */
int16_t ds3231_time_year_get(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 содержимое регистра смещения старения (Aging Offset). * @note См. даташит DS3231 для специфики Aging Offset * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b int8_t - один байт со знаком, представляющий смещение старения. */
int8_t ds3231_aging_offset_get(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 содержимое регистра температуры. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b float - Float, представляющий температуры с шагом 0.25° C. */
float ds3231_temperature_get(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 содержимое регистров управления (Control) и состояния (Status). * @note См. даташит DS3231 для полного описания всех значений управления и статуса. * @note Возвращенное значение должно быть освобождено вызывающим кодом, чтобы не было утечки памяти. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b rtc_control_status_t* - Указатель на структуру, содержащую все значения регистра * управления и статуса. */
rtc_control_status_t* ds3231_control_status_flags_get(rtc_handle_t* rtc_handle);

/** * @brief Запрашивает у DS3231 текущее значение времени, возвращенное как \b struct \b tm. * @note Возвращенное значение должно быть освобождено вызывающим кодом, чтобы не было утечки памяти. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b struct \b tm* - указатель на структуру tm, заполненную текущим временем. */
struct tm* ds3231_time_get(rtc_handle_t* rtc_handle);

/** * @brief Установит время DS3231, используя значение \b time_t * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param time [in] time_t, которое будет установлено в DS3231 * @return @b esp_err_t - каскадируется из i2c_master_transmit */
esp_err_t ds3231_time_time_t_set(rtc_handle_t* rtc_handle, time_t time);

/** * @brief Запрашивает у DS3231 значение текущего времени, возвращаемое как \b struct \b tm. * @note Хотя семейство ESP32 32-разрядное, time_t имеет разрядность 64 бита и совместимо с Y2038 * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b time_t - целочисленное значение без знака, представляющее количество секунд, прошедших от * момента 1 января 1970, 00:00:00 */
time_t ds3231_time_unix_get(rtc_handle_t* rtc_handle);

/** * @brief Установит время DS3231, используя значение времени Unix * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param unix_time [in] long, которое установит время в секундах с момента 1 января 1970 @ 00:00:00 * @return @b esp_err_t - каскадируется из i2c_master_transmit */
esp_err_t ds3231_time_unix_set(rtc_handle_t* rtc_handle, long unix_time);

/** * @brief Установит время DS3231, используя значение \b struct \b tm * @note the Значение \b time \b ДОЛЖНО иметь \b ОБА установленные поля недели (tm.tm_wday) * и дня месяца (tm.tm_mday) * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param time [in] структура tm, поля которой установлены в желаемые значения времени. * @return @b esp_err_t - каскадируется из i2c_master_transmit */
esp_err_t ds3231_time_tm_set(rtc_handle_t* rtc_handle, struct tm time);

/** * @brief Создаст прерывание по сигналу на выводе порта (GPIO Pin interrupt) и соответствующую * очередь обработки, а также назначит определяемую пользователем функцию для обработки * прерываний, генерируемых сигналом на выводе INT DS3231. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param INT [in] gpio_num_t ножка GPIO, к которой подключен вывод INT DS3231. * @param isr [in] gpio_isr_t определяемая пользователем функция, запускаемая событием прерывания. * @param params [in] void* указатель на параметры, переданные в \b isr, * @return \b esp_err_t - каскадируется из gpio_isr_handler_add */
esp_err_t ds3231_alarm_isr_create(rtc_handle_t* rtc_handle, gpio_num_t INT, gpio_isr_t isr, void* params);

/** * @brief Удаляет alarm isr, ранее созданный вызовом \b ds3231_alarm_isr_create * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param INT [in] gpio_num_t ножка GPIO, к которой подключен вывод INT DS3231. * @return \b esp_err_t - cascaded from gpio_isr_handler_delete */
esp_err_t ds3231_alarm_isr_delete(rtc_handle_t* rtc_handle, gpio_num_t INT);

/** * @brief Запрашивает у DS3231 установку значения Alarm 1. * @attention Из-за отличий в том, как DS3231 и \b struct \b tm хранят значения дня недели/месяца, * будет появляться -1 в tm.tm_wday или tm.tm_mday (или в обоих), чтобы показать недопустимое значение. * @attention Если \a tm.tm_wday или \a tm.tm_mday имеет значение -1, и в другом регистре значение >= 0, * то это нормальная ситуация, потому что только день недели или день месяца может быть * использовано для определенной установки времени будильника. * @note Возвращенное значение должно быть освобождено вызывающим кодом, чтобы не было утечки памяти. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b struct \b tm* - указатель на структуру tm, заполненную временем Alarm 1. */
struct tm* ds3231_alarm1_time_get(rtc_handle_t* rtc_handle);

/** * @brief Установит значение Alarm 1 для срабатывания на одном и том же дне каждой недели. * Alarm 1 поддерживает значение секунд, в то время как Alarm 2 секунды не поддерживает. * В остальном их функционал одинаковый. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param dow [in] enum rtc_day_of_week_e (это передчисление соответствует тому, как DS3231 * представляет день недели). * @param hour [in] int8_t представляет часы 00 - 23. * @param minutes [in] int8_t представляет минуты 00 - 59. * @param seconds [in] int8_t представляет секунды 00 - 59. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm1_day_of_week_set(rtc_handle_t* rtc_handle, enum rtc_day_of_week_e dow, int8_t hour, int8_t minutes, int8_t seconds);

/** * @brief Установит значение Alarm 1 для срабатывания на одном и том же дне каждого месяца. * Alarm 1 поддерживает значение секунд, в то время как Alarm 2 секунды не поддерживает. * В остальном их функционал одинаковый. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param day [in] int8_t представляет день месяца. * @note Если день месяца не существует в текущем месяце, например 30 число февраля, то alarm * не сработает в этом месяце. * Рекомендуется добавить логику в alarm ISR, чтобы подстроить запись alarm после его срабатывания. * @param hour [in] int8_t представляет часы 00 - 23. * @param minutes [in] int8_t представляет минуты 00 - 59. * @param seconds [in] int8_t представляет секунды 00 - 59. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm1_day_of_month_set(rtc_handle_t* rtc_handle, int8_t day, int8_t hour, int8_t minutes, int8_t seconds);

/** * @brief Возвратит двоичное значение, представляющее разрешенность Alarm 1 * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true - Alarm 1 разрешен. * @retval false - Alarm 1 запрещен. */
bool ds3231_alarm1_enable_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит состояние разрешено/запрещено для Alarm 1 * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешить или запретить Alarm 1 * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm1_enable_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Получит статус срабатывания Alarm 1. Если сконфигурированы прерывания alarm, то они сработают. * Этот флаг остается установленным, пока не будет сброшен вручную. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true - сработал Alarm 1. * @retval false - Alarm 1 не срабатывал. */
bool ds3231_alarm1_fired_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Получит условия срабатывания Alarm 1, как это описано в \b rtc_alarm_rate_e. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b enum \b rtc_alarm_rate_e - значение перечисления, идентифицирующее условие срабатывания */
enum rtc_alarm_rate_e ds3231_alarm1_rate_get(rtc_handle_t* rtc_handle);

/** * @brief Установит условие срабатывания Alarm 1, как это описано в \b rtc_alarm_rate_e. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param alarm_rate [in] значение перечисление, идентифицирующее условие срабатывания. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm1_rate_set(rtc_handle_t* rtc_handle, enum rtc_alarm_rate_e alarm_rate);

/** * @brief Сбросит в 0 флаг срабатывания Alarm 1. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm1_fired_flag_reset(rtc_handle_t* rtc_handle);

/** * @brief Запросит у DS3231 установленное значение Alarm 2. * @attention Из-за отличий в том, как DS3231 и \b struct \b tm хранят значения дня недели/месяца, * будет появляться -1 в tm.tm_wday или tm.tm_mday (или в обоих), чтобы показать * недопустимое значение. * @attention Если \a tm.tm_wday или \a tm.tm_mday имеет значение -1, и в другом регистре значение >= 0, * то это нормальная ситуация, потому что только день недели или день месяца может быть * использовано для определенной установки времени будильника. * @note Возвращенное значение должно быть освобождено вызывающим кодом, чтобы не было утечки памяти. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b struct \b tm* - указатель на структуру tm, заполененную временем Alarm 2. */
struct tm* ds3231_alarm2_time_get(rtc_handle_t* rtc_handle);

/** * @brief Установит значение Alarm 2, чтобы он срабатывал в один и тот же день недели. * Alarm 1 поддерживает секунды, а Alarm 2 секунды не поддерживает. * В остальном их функционал одинаковый. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param dow [in] enum rtc_day_of_week_e (это перечисление соответствует тому, как DS3231 * представляет день недели). * @param hour [in] int8_t представляет часы 00 - 23. * @param minutes [in] int8_t представляет минуты 00 - 59. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm2_day_of_week_set(rtc_handle_t* rtc_handle, enum rtc_day_of_week_e dow, int8_t hour, int8_t minutes);

/** * @brief Установит значение Alarm 2, чтобы он срабатывал в один и тот же день каждого месяца. * Alarm 1 поддерживает секунды, а Alarm 2 секунды не поддерживает. * В остальном их функционал одинаковый. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param day [in] int8_t представляет день месяца. * @note Если день месяца не существует в текущем месяце, например 30 число февраля, * то alarm не сработает в этом месяце. Рекомендуется добавить логику в alarm ISR, * чтобы подстроить запись alarm после его срабатывания. * @param hour [in] int8_t представляет часы 00 - 23. * @param minutes [in] int8_t представляет минуты 00 - 59. * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm2_day_of_month_set(rtc_handle_t* rtc_handle, int8_t day, int8_t hour, int8_t minutes);

/** * @brief Вернет двоичное значение, представляющее состояние разрешен/запрещен будильника Alarm 2 * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true - Alarm 2 разрешен. * @retval false - Alarm 2 запрещен. */
bool ds3231_alarm2_enable_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит состояние разрешен/запрещен будильника Alarm 2 * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешен или запрещен Alarm 2 * @return @b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm2_enable_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Получит статус флага срабатывания Alarm 2. Если сконфигурированы прерывания alarm, * то они сработают. Этот флаг остается установленным, пока не будет сброшен вручную. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true - сработал Alarm 2. * @retval false - Alarm 2 не срабатывал. */
bool ds3231_alarm2_fired_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Получит условие срабатывания Alarm 2, как это описано в \b rtc_alarm_rate_e. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b enum \b rtc_alarm_rate_e - значение перечисления, идентифицирующее условие срабатывания */
enum rtc_alarm_rate_e ds3231_alarm2_rate_get(rtc_handle_t* rtc_handle);

/** * @brief Установит условие срабатывания Alarm 2, как это описано \b rtc_alarm_rate_e. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param alarm_rate [in] значение перечисление, идентифицирующее условие срабатывания. * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm2_rate_set(rtc_handle_t* rtc_handle, enum rtc_alarm_rate_e alarm_rate);

/** * @brief Сбросит в 0 флаг срабатывания Alarm 2. * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_alarm2_fired_flag_reset(rtc_handle_t* rtc_handle);

/** * @brief Синхронизирует время ESP32 с временем из DS3231 * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval 0 успех * @retval -1 неудача */
int ds3231_set_esp_with_rtc(rtc_handle_t* rtc_handle);

/** * @brief Получит статус флага генератора (Oscillartor Flag) * * @note Драйвер знает, что аппаратура разрешена при Logic 0, и вернет true для Logic 0 * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешен * @retval false запрещен */
bool ds3231_enable_oscillator_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит статус флага генератора (Oscillartor Flag) * * @note Драйвер знает, что аппаратура разрешена при Logic 0, и установит Logic 0 для * \b isEnabled \b = \b true * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешить/запретить Oscillator Flag * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_enable_oscillator_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Получит статус флага генерации выходного прямоугольного сигнала при работе * от батареи (Battery Backed Scquare Wave Flag) * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешено * @retval false запрещено */
bool ds3231_battery_backed_square_wave_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит состояние Batter Backed Square Wave Flag * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешить/запретить генерацию прямоугольника при работе от батареи * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_battery_backed_square_wave_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Вернет состояние флага преобразования температуры (Convert Temp Temperature Flag) * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешено * @retval false запрещено */
bool ds3231_convert_temp_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит состояние Convert Temperature Flag * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешить/запретить Convert Temperature Flag * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_convert_temp_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Получит текущее значение (1 .. 4) настройки выхода генерации прямогольника * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return значение перечисления rtc_square_wave_freq_e (соответствует частоте прямоугольного сигнала) */
enum rtc_square_wave_freq_e ds3231_square_wave_freq_get(rtc_handle_t* rtc_handle);

/** * @brief Установит значение перечисления (1 .. 4) для настройки генерируемого прямоугольного сигнала * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param frequency [in] rtc_square_wave_freq_e желаемая выходная частота (один из 4 вариантов). * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_square_wave_freq_set(rtc_handle_t* rtc_handle, enum rtc_square_wave_freq_e frequency);

/** * @brief Получит статус Interupt/Square Wave Flag * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешены прерывания будильника (Alarm Interrupts) * @retval false постоянная генерация прямоугольного сигнала */
enum rtc_intr_sqr_e ds3231_interrupt_square_wave_control_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит значение флага управления формированием прямоугольника * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешит/запретит флаг * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_interrupt_square_wave_control_flag_set(rtc_handle_t* rtc_handle, enum rtc_intr_sqr_e isEnabled);

/** * @brief Получит состояние флага остановки генератора (Ocsillator Stop Flag) * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешено * @retval false запрещено */
bool ds3231_get_oscillator_stop_flag(rtc_handle_t* rtc_handle);

/** * @brief Сбросит состояние Ocsillator Stop Flag * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_oscillator_stop_flag_reset(rtc_handle_t* rtc_handle);

/** * @brief Получит состояние флага генерации 32kHz * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true разрешено * @retval false запрещено */
bool ds3231_32kHz_out_enable_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Установит состояние флага генерации 32kHz * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param isEnabled [in] разрешить/запретить 32kHz * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_32kHz_out_enable_flag_set(rtc_handle_t* rtc_handle, bool isEnabled);

/** * @brief Получит состояние флага занятости (Busy Flag) * * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @retval true DS3231 занята * @retval false DS3231 не занята */
bool ds3231_busy_flag_get(rtc_handle_t* rtc_handle);

/** * @brief Подобная концепция в ds3231_set_registers_raw. Позволяет установить один регистр * одним байтом данных. * @warning Это потенциально опасная команда, поскольку никаких защитных проверок данных * не проводится. Эта функция предоставляется для того, чтобы обеспечить низкоуровневый * доступ, который не предоставляется другими функциями. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_register [in] enum rtc_register_e записываемый регистр * @param bit_pattern [in] uint8_t записываемое значение * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_register_set(rtc_handle_t* rtc_handle, enum rtc_register_e rtc_register, uint8_t bit_pattern);

/** * @brief Подобная концепция в ds3231_register_set. Позволяет установить несколько идущих * друг за другом регистров из массива данных. * * @warning Это потенциально опасная команда, поскольку никаких защитных проверок данных * не проводится. Эта функция предоставляется для того, чтобы обеспечить низкоуровневый * доступ, который не предоставляется другими функциями. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. * @param rtc_data [in] uint8_t массив данных, записываемых в регистры (регистры). * @param count [in] size_t количество элементов в rtc_data * @return \b esp_err_t - каскадируется из i2c_master_transmit. */
esp_err_t ds3231_set_registers_raw(rtc_handle_t* rtc_handle, uint8_t* rtc_data, size_t count);

/** * @brief Получит все регистры времени, будильника и управления/статуса. Данные выводятся * функцией ESP_LOGI. * @note Это хороший способ проверить, какие данные установлены в DS3231. * @note Если уровень отладки (debug level) в VERBOSE, то напечатается список каждого * регистра и его значения в форматах hex и binary. */
void ds3231_debug_print_data(rtc_handle_t* rtc_handle);

/** * @brief Получит и установит/сбросит все флаги из регистров управления/статуса. Данные выводятся * функцией ESP_LOGI * @warning Эта функция должна использоваться только для отладки/тестирования DS3231. * Существующие настройки будут перезаписаны. * @param rtc_handle [in] rtc_handle_t* дескриптор, возвращенный из ds3231_init. */
void ds3231_debug_test_set(rtc_handle_t* rtc_handle);

#ifdef __cplusplus }
#endif

[Ссылки]

1. ds3231 - Driver for DS1337 RTC and DS3231 high precision RTC module site:esp-idf-lib.readthedocs.io.
2. nopnop2002 / esp-idf-ds3231.
3. nopnop2002 / esp-idf-ds1302.
4. nopnop2002 / esp-idf-ds1307.
5. nopnop2002 / esp-idf-pcf8563.
6. Сравнение точности микросхем RTC.