RCM — ESP32 Room Controller
WT32-ETH01 firmware
Loading...
Searching...
No Matches
ds3231.c
Go to the documentation of this file.
1
8#include "ds3231.h"
9
10#include "driver/i2c_master.h"
11#include "esp_check.h"
12#include "esp_log.h"
13#include "freertos/FreeRTOS.h"
14#include "freertos/task.h"
15#include "i2c_bus.h"
16
17static const char *TAG = "ds3231";
18
20#define DS3231_I2C_ADDR 0x68
21
22/* Регистры времени */
23#define DS3231_REG_SECONDS 0x00
24#define DS3231_REG_MINUTES 0x01
25#define DS3231_REG_HOURS 0x02
26#define DS3231_REG_DAY 0x03
27#define DS3231_REG_DATE 0x04
28#define DS3231_REG_MONTH 0x05
29#define DS3231_REG_YEAR 0x06
30
31/* Управляющие / служебные */
32#define DS3231_REG_CONTROL 0x0E
33#define DS3231_REG_STATUS 0x0F
34#define DS3231_REG_TEMP_MSB 0x11
35#define DS3231_REG_TEMP_LSB 0x12
36
37#define DS3231_STATUS_OSF (1U << 7)
38#define DS3231_HOURS_12H (1U << 6)
39
40#define DS3231_YEAR_BASE 2000U
41
42static i2c_master_dev_handle_t s_dev;
43static bool s_initialized;
44
45static uint8_t bcd_to_bin(uint8_t bcd)
46{
47 return (uint8_t)(((bcd >> 4) * 10U) + (bcd & 0x0FU));
48}
49
50static uint8_t bin_to_bcd(uint8_t bin)
51{
52 return (uint8_t)(((bin / 10U) << 4) | (bin % 10U));
53}
54
55static esp_err_t ds3231_write_regs(uint8_t reg, const uint8_t *data, size_t len)
56{
57 uint8_t buf[1 + 7];
58
59 ESP_RETURN_ON_FALSE(data != NULL && len > 0 && len <= 7, ESP_ERR_INVALID_ARG,
60 TAG, "bad write args");
61
62 buf[0] = reg;
63 for (size_t i = 0; i < len; i++) {
64 buf[1 + i] = data[i];
65 }
66 return i2c_master_transmit(s_dev, buf, 1 + len, I2C_BUS_TIMEOUT_MS);
67}
68
69static esp_err_t ds3231_read_regs(uint8_t reg, uint8_t *data, size_t len)
70{
71 ESP_RETURN_ON_FALSE(data != NULL && len > 0, ESP_ERR_INVALID_ARG, TAG, "bad read args");
72 return i2c_master_transmit_receive(s_dev, &reg, 1, data, len, I2C_BUS_TIMEOUT_MS);
73}
74
76{
77 ESP_RETURN_ON_FALSE(dt != NULL, ESP_ERR_INVALID_ARG, TAG, "null dt");
78 ESP_RETURN_ON_FALSE(dt->year >= DS3231_YEAR_BASE && dt->year <= DS3231_YEAR_BASE + 99U,
79 ESP_ERR_INVALID_ARG, TAG, "year out of range");
80 ESP_RETURN_ON_FALSE(dt->month >= 1 && dt->month <= 12, ESP_ERR_INVALID_ARG, TAG, "month");
81 ESP_RETURN_ON_FALSE(dt->date >= 1 && dt->date <= 31, ESP_ERR_INVALID_ARG, TAG, "date");
82 ESP_RETURN_ON_FALSE(dt->weekday >= 1 && dt->weekday <= 7, ESP_ERR_INVALID_ARG, TAG, "weekday");
83 ESP_RETURN_ON_FALSE(dt->hour <= 23, ESP_ERR_INVALID_ARG, TAG, "hour");
84 ESP_RETURN_ON_FALSE(dt->minute <= 59, ESP_ERR_INVALID_ARG, TAG, "minute");
85 ESP_RETURN_ON_FALSE(dt->second <= 59, ESP_ERR_INVALID_ARG, TAG, "second");
86 return ESP_OK;
87}
88
89esp_err_t ds3231_init(void)
90{
91 uint8_t status = 0;
92 esp_err_t err = ESP_OK;
93 int attempt;
94
95 if (s_initialized) {
96 return ESP_OK;
97 }
98
99 ESP_RETURN_ON_ERROR(i2c_bus_init(), TAG, "shared bus init failed");
100 ESP_RETURN_ON_ERROR(i2c_bus_add_device(DS3231_I2C_ADDR, &s_dev), TAG, "add device failed");
101
102 /* Несколько попыток: после включения питания модуль может ответить не с первого раза */
103 for (attempt = 1; attempt <= 3; attempt++) {
104 err = ds3231_read_regs(DS3231_REG_STATUS, &status, 1);
105 if (err == ESP_OK) {
106 break;
107 }
108 ESP_LOGW(TAG, "probe 0x%02X attempt %d/3 failed: %s",
109 DS3231_I2C_ADDR, attempt, esp_err_to_name(err));
110 vTaskDelay(pdMS_TO_TICKS(20));
111 }
112
113 if (err != ESP_OK) {
114 ESP_LOGE(TAG, "DS3231 not responding at 0x%02X (%s). Check wiring/power/pull-ups",
115 DS3231_I2C_ADDR, esp_err_to_name(err));
116 (void)i2c_master_bus_rm_device(s_dev);
117 s_dev = NULL;
118 return err;
119 }
120
121 s_initialized = true;
122 ESP_LOGI(TAG, "DS3231 at 0x%02X, status=0x%02X%s",
123 DS3231_I2C_ADDR, status,
124 (status & DS3231_STATUS_OSF) ? " (OSF: time may be invalid)" : "");
125 return ESP_OK;
126}
127
129{
130 uint8_t raw[7];
131
132 ESP_RETURN_ON_FALSE(s_initialized, ESP_ERR_INVALID_STATE, TAG, "not initialized");
133 ESP_RETURN_ON_FALSE(dt != NULL, ESP_ERR_INVALID_ARG, TAG, "null dt");
134
135 ESP_RETURN_ON_ERROR(ds3231_read_regs(DS3231_REG_SECONDS, raw, sizeof(raw)),
136 TAG, "read time failed");
137
138 dt->second = bcd_to_bin(raw[0] & 0x7FU);
139 dt->minute = bcd_to_bin(raw[1] & 0x7FU);
140
141 /* Всегда читаем как 24h; если чип в 12h — конвертируем */
142 if (raw[2] & DS3231_HOURS_12H) {
143 uint8_t hour12 = bcd_to_bin(raw[2] & 0x1FU);
144 bool pm = (raw[2] & (1U << 5)) != 0;
145 if (hour12 == 12) {
146 dt->hour = pm ? 12 : 0;
147 } else {
148 dt->hour = (uint8_t)(pm ? hour12 + 12 : hour12);
149 }
150 } else {
151 dt->hour = bcd_to_bin(raw[2] & 0x3FU);
152 }
153
154 dt->weekday = bcd_to_bin(raw[3] & 0x07U);
155 dt->date = bcd_to_bin(raw[4] & 0x3FU);
156 dt->month = bcd_to_bin(raw[5] & 0x1FU);
157 dt->year = (uint16_t)(DS3231_YEAR_BASE + bcd_to_bin(raw[6]));
158
159 return ESP_OK;
160}
161
163{
164 uint8_t raw[7];
165
166 ESP_RETURN_ON_FALSE(s_initialized, ESP_ERR_INVALID_STATE, TAG, "not initialized");
167 ESP_RETURN_ON_ERROR(ds3231_validate_datetime(dt), TAG, "invalid datetime");
168
169 raw[0] = bin_to_bcd(dt->second);
170 raw[1] = bin_to_bcd(dt->minute);
171 raw[2] = bin_to_bcd(dt->hour); /* бит 6 = 0 → 24-часовой режим */
172 raw[3] = bin_to_bcd(dt->weekday);
173 raw[4] = bin_to_bcd(dt->date);
174 raw[5] = bin_to_bcd(dt->month);
175 raw[6] = bin_to_bcd((uint8_t)(dt->year - DS3231_YEAR_BASE));
176
177 ESP_RETURN_ON_ERROR(ds3231_write_regs(DS3231_REG_SECONDS, raw, sizeof(raw)),
178 TAG, "write time failed");
179
180 /* После установки времени OSF сбрасываем */
181 return ds3231_clear_osf();
182}
183
184esp_err_t ds3231_get_temperature(float *temp_c)
185{
186 uint8_t raw[2];
187
188 ESP_RETURN_ON_FALSE(s_initialized, ESP_ERR_INVALID_STATE, TAG, "not initialized");
189 ESP_RETURN_ON_FALSE(temp_c != NULL, ESP_ERR_INVALID_ARG, TAG, "null temp");
190
191 ESP_RETURN_ON_ERROR(ds3231_read_regs(DS3231_REG_TEMP_MSB, raw, sizeof(raw)),
192 TAG, "read temp failed");
193
194 /* MSB — целая часть (signed), LSB[7:6] — дробная с шагом 0.25 °C */
195 int8_t whole = (int8_t)raw[0];
196 float frac = (float)((raw[1] >> 6) & 0x03U) * 0.25f;
197 *temp_c = (float)whole + frac;
198 return ESP_OK;
199}
200
201esp_err_t ds3231_is_oscillator_stopped(bool *stopped)
202{
203 uint8_t status = 0;
204
205 ESP_RETURN_ON_FALSE(s_initialized, ESP_ERR_INVALID_STATE, TAG, "not initialized");
206 ESP_RETURN_ON_FALSE(stopped != NULL, ESP_ERR_INVALID_ARG, TAG, "null stopped");
207
208 ESP_RETURN_ON_ERROR(ds3231_read_regs(DS3231_REG_STATUS, &status, 1),
209 TAG, "read status failed");
210 *stopped = (status & DS3231_STATUS_OSF) != 0;
211 return ESP_OK;
212}
213
214esp_err_t ds3231_clear_osf(void)
215{
216 uint8_t status = 0;
217
218 ESP_RETURN_ON_FALSE(s_initialized, ESP_ERR_INVALID_STATE, TAG, "not initialized");
219
220 ESP_RETURN_ON_ERROR(ds3231_read_regs(DS3231_REG_STATUS, &status, 1),
221 TAG, "read status failed");
222 status &= (uint8_t)~DS3231_STATUS_OSF;
223 return ds3231_write_regs(DS3231_REG_STATUS, &status, 1);
224}
#define DS3231_HOURS_12H
Definition ds3231.c:38
esp_err_t ds3231_set_time(const ds3231_datetime_t *dt)
Записать дату и время в DS3231 (24-часовой режим).
Definition ds3231.c:162
#define DS3231_I2C_ADDR
7-битный адрес DS3231 на шине
Definition ds3231.c:20
esp_err_t ds3231_init(void)
Добавляет DS3231 на общую I2C-шину и проверяет доступность.
Definition ds3231.c:89
static i2c_master_dev_handle_t s_dev
Definition ds3231.c:42
esp_err_t ds3231_get_temperature(float *temp_c)
Прочитать температуру с встроенного датчика DS3231.
Definition ds3231.c:184
static const char * TAG
Definition ds3231.c:17
static uint8_t bin_to_bcd(uint8_t bin)
Definition ds3231.c:50
static esp_err_t ds3231_read_regs(uint8_t reg, uint8_t *data, size_t len)
Definition ds3231.c:69
static bool s_initialized
Definition ds3231.c:43
esp_err_t ds3231_get_time(ds3231_datetime_t *dt)
Прочитать текущие дату и время из DS3231.
Definition ds3231.c:128
static esp_err_t ds3231_write_regs(uint8_t reg, const uint8_t *data, size_t len)
Definition ds3231.c:55
static esp_err_t ds3231_validate_datetime(const ds3231_datetime_t *dt)
Definition ds3231.c:75
esp_err_t ds3231_is_oscillator_stopped(bool *stopped)
Проверить, был ли остановлен осциллятор (потеря питания / батареи).
Definition ds3231.c:201
static uint8_t bcd_to_bin(uint8_t bcd)
Definition ds3231.c:45
#define DS3231_REG_TEMP_MSB
Definition ds3231.c:34
#define DS3231_REG_SECONDS
Definition ds3231.c:23
esp_err_t ds3231_clear_osf(void)
Сбросить флаг OSF в Status-регистре.
Definition ds3231.c:214
#define DS3231_YEAR_BASE
Definition ds3231.c:40
#define DS3231_STATUS_OSF
Definition ds3231.c:37
#define DS3231_REG_STATUS
Definition ds3231.c:33
Драйвер часов реального времени Maxim DS3231 (I2C).
esp_err_t i2c_bus_init(void)
Создаёт master-шину I2C (идемпотентно).
Definition i2c_bus.c:16
esp_err_t i2c_bus_add_device(uint8_t addr7, i2c_master_dev_handle_t *dev)
Добавить устройство с 7-битным адресом на общую шину.
Definition i2c_bus.c:43
Общая I2C-шина master (I2C_NUM_0) для всех периферийных устройств.
#define I2C_BUS_TIMEOUT_MS
Definition i2c_bus.h:20
Дата и время DS3231.
Definition ds3231.h:21
uint8_t month
1…12
Definition ds3231.h:23
uint8_t date
1…31
Definition ds3231.h:24
uint8_t weekday
1…7
Definition ds3231.h:25
uint16_t year
2000…2099
Definition ds3231.h:22
uint8_t hour
0…23
Definition ds3231.h:26
uint8_t minute
0…59
Definition ds3231.h:27
uint8_t second
0…59
Definition ds3231.h:28