DS1307 RTC Module
The DS1307 is an I2C real-time clock (RTC) chip. It is a low-power, full BCD-code clock/calendar real-time clock chip with 56 bytes of non-volatile RAM. Address and data are transferred via a two-wire bidirectional serial bus. The chip can provide seconds, minutes, hours, and other information, and the number of days in each month is automatically adjusted. It also features leap year compensation. The AM/PM flag determines whether the clock operates in 24-hour or 12-hour mode. The chip has a built-in power-sense circuit with power-fail detection and battery switchover functions.
Module Source
Purchase link: https://item.taobao.com/item.htm?spm=a1z10.3-c-s.w4002-24706531953.10.2b4a6a4bH7IysA&id=522553351753 Materials download link: https://pan.baidu.com/s/1BcLbfV5bCjKdAS4PL3BRnA Extraction code: 6uq7
Specifications
Operating voltage: 4.5-5.5V Operating current: 1.5 mA Module size: 27mm28mm8.4mm Control method: I2C Actual number of pins used: 4 Pin (2.54mm pitch header)
Note: Comes with a battery, has power-fail detection and battery switchover functions.
View Materials
Schematic description:
- The module carries two chips: the DS1307 clock chip and the AT24C32 data storage chip. Both use I2C communication. Although they share the same interface, their device addresses are different, so they can be operated simultaneously.
- The module carries a DS18B20 digital temperature sensor interface. The DS pin routed out on the module is the data output pin of the temperature sensor, but the module does not include the temperature sensor — it needs to be installed separately.
- The SQ pin on the module is the square-wave output pin of the DS1307. Controlled by an internal register, it can output one of four square-wave frequencies (1 Hz, 4 kHz, 8 kHz, 32 kHz). Note that the SQ pin is an open-drain output and requires an external pull-up resistor.
Read/Write Process Description What we mainly implement is time reading and time setting. The I2C principle will not be explained here; please refer to other sources. Read timing: Send I2C START signal -> Send device address + 0 -> Wait for module ACK -> After ACK, send register address -> Wait for module ACK -> After ACK, send START signal again -> Send device address + 1 -> Wait for module ACK -> Read data -> After reading, master sends NACK -> Send I2C STOP signal.
Write timing: Send I2C START signal -> Send device address + 0 -> Wait for module ACK -> After ACK, send register address -> Wait for module ACK -> After ACK, send data -> After sending, wait for module ACK -> Send I2C STOP signal.
Related Register Description Time and calendar information is obtained by reading the appropriate register bytes. The figure below shows the RTC registers. Time and calendar are set or initialized by writing the appropriate register bytes. The contents of the time and calendar registers are in BCD format. The value corresponding to the day of the week is user-defined but must be continuous (for example, if 1 equals Sunday, then 2 equals Monday, etc.). Illogical time and date entries will result in undefined operation. Bit 7 of register 00h (BIT 7) is the Clock Halt (CH) bit. When this bit is set to 1, the oscillator is disabled. When cleared to 0, the oscillator is enabled.
When power is first applied to the device, the time and date registers are typically reset to 01/01/00 01 00:00:00 (MM/DD/YY DOW HH:MM:SS). The CH bit in the seconds register will be set to 1. When the timing function is not needed, the clock can be halted (set CH to 1) to minimize supply current.
Example:
// add: register address to write dat: data to write
uint8_t Write1307(uint8_t add,
uint8_t dat)
{
unsigned char temp;
/* Decimal to BCD code conversion */
temp=dat/10;
temp<<=4;
temp=dat%10+temp;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
int err=0;
i2c_master_start(cmd);
err = i2c_master_write_byte(cmd, 0xD0, ACK_CHECK_EN);
i2c_master_write_byte(cmd, add, ACK_CHECK_EN);
i2c_master_write_byte(cmd, temp, ACK_CHECK_EN);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_1, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return (0);
}
Write1307(0x00,0); // Set seconds
Write1307(0x01,57); // Set minutes
Write1307(0x02,13); // Set hours
Write1307(0x03,5); // Set day of week
Write1307(0x04,7); // Set date
Write1307(0x05,4); // Set month
Write1307(0x06,23); // Set year2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Porting Process
Pin Selection
Port to Project
Our goal is to port the example to the ESP32-S3 dev board. Complete driver code has been provided for you. Follow the steps below to complete the porting.
For detailed instructions on creating folders and new .c and .h files, refer to section 1.4.2 in the [DHT11 Temperature and Humidity Sensor] chapter; we will not repeat it here.
Just note that here we change the file names bsp_dht11.c and bsp_dht11.h to bsp_ds1307.c and bsp_ds1307.h, and the folder name to DS1307.
Write Code
In the file bsp_ds1307.c, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-12 LCKFB-lp first version
*/
#include "bsp_ds1307.h"
#include "stdio.h"
#include "sys/unistd.h"
// Time data structure
_time_struct_ RTC_Time = {0};
static void delay_ms(unsigned int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
static void delay_us(unsigned int us)
{
ets_delay_us(us);
}
static void delay_1ms(unsigned int ms)
{
vTaskDelay(ms / portTICK_PERIOD_MS);
}
static void delay_1us(unsigned int us)
{
ets_delay_us(us);
}
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
/******************************************************************
* Function Name: DS1307_GPIO_Init
* Function Description: Initialize the I2C pins
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes: None
******************************************************************/
void DS1307_GPIO_Init(void)
{
int i2c_master_port = I2C_NUM_1;//I2C_NUMBER(CONFIG_I2C_SLAVE_PORT_NUM);
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_SDA,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = GPIO_SCL,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
// .clk_flags = 0, /*!< Optional, you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here. */
};
esp_err_t err = i2c_param_config(i2c_master_port, &conf);
// Register the I2C service, i.e., enable it
i2c_driver_install(I2C_NUM_1, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
}
/******************************************************************
* Function Name: Write1307
* Function Description: Write data dat to address add in the DS1307
* Function Parameters: add: register address to write dat: data to write
* Function Return: 0 write successful 1 no ACK when writing device address 2 no ACK when writing register address
* Author: LC
* Notes: Device address = 0xD0
******************************************************************/
unsigned char Write1307(unsigned char add,unsigned char dat)
{
unsigned char temp;
/* Decimal to BCD code conversion */
temp=dat/10;
temp<<=4;
temp=dat%10+temp;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
int err=0;
i2c_master_start(cmd);
err = i2c_master_write_byte(cmd, 0xD0, ACK_CHECK_EN);
i2c_master_write_byte(cmd, add, ACK_CHECK_EN);
i2c_master_write_byte(cmd, temp, ACK_CHECK_EN);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_1, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return (0);
}
/******************************************************************
* Function Name: Read1307
* Function Description: Read time data from the DS1307
* Function Parameters: add: register address to read
* Function Return: 255 - read failed; other values - read successful
* Author: LC
* Notes: None
******************************************************************/
unsigned char Read1307(unsigned char add)
{
int i =0;
unsigned char temp;
unsigned char dat;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, 0xD0, ACK_CHECK_EN);
i2c_master_write_byte(cmd, add, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, 0xD1, ACK_CHECK_EN);
i2c_master_read_byte(cmd, &dat, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_1, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
/* BCD code to decimal conversion */
temp=dat/16;
dat=dat%16;
dat=dat+temp*10;
return(dat);
}
/******************************************************************
* Function Name: get_RTC_time
* Function Description: Get the DS1307 time
* Function Parameters: None
* Function Return: None
* Author: LC
* Notes: None
******************************************************************/
void Get_RTC_Time(void)
{
RTC_Time.sec = Read1307(0x00);
RTC_Time.min = Read1307(0x01);
RTC_Time.hour = Read1307(0x02);
RTC_Time.week = Read1307(0x03);
RTC_Time.date = Read1307(0x04);
RTC_Time.month = Read1307(0x05);
RTC_Time.year = Read1307(0x06);
}
/******************************************************************
* Function Name: set_RTC_time
* Function Description: Set the RTC time
* Function Parameters: year: year range 00-99 (last two digits of the year)
* month: month range 01-12
* date: date range 01-31
* week: weekday range 01-07
* hour: hour range 01-12 or 00-23
* min: minute range 00-59
* sec: second range 00-59
* Function Return:
* Author: LC
* Notes: e.g. to set time 2023-4-7 - Friday -13:57:00
* set_RTC_time(23, 4, 7, 5, 13, 57, 0)
******************************************************************/
void Set_RTC_Time(uint8_t year,uint8_t month,uint8_t date,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec)
{
Write1307(0x00,sec); // Set seconds
Write1307(0x01,min); // Set minutes
Write1307(0x02,hour); // Set hours
Write1307(0x03,week); // Set weekday
Write1307(0x04,date); // Set date
Write1307(0x05,month); // Set month
Write1307(0x06,year); // Set year
}
/*******************************************************************************
* Function Name: AT24CXX_ReadByte
* Description: Read one byte of data starting from the specified address in the serial EEPROM
* Input: _usAddress address
* Output: read data dat
* Calls:
* Notes:
*******************************************************************************/
uint8_t AT24CXX_ReadByte(uint16_t addr)
{
uint8_t u8Data = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);// START signal
i2c_master_write_byte(cmd, 0xA0 | 0, ACK_CHECK_EN);// Device addressing + read/write selection
i2c_master_write_byte(cmd, (uint8_t)((addr >> 8) & 0xFF), ACK_CHECK_EN);
i2c_master_write_byte(cmd, (uint8_t)(addr & 0xFF), ACK_CHECK_EN);
i2c_master_start(cmd);// START signal
i2c_master_write_byte(cmd, 0xA0 | 1, ACK_CHECK_EN);// Device addressing + read
i2c_master_read_byte(cmd, &u8Data, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_1, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return u8Data;
}
/*******************************************************************************
* Function Name: AT24CXX_WriteByte
* Description: Write one byte of data starting from the specified address in the serial EEPROM
* Input: addr address, data
* Output: void
* Calls:
* Notes:
*******************************************************************************/
void AT24CXX_WriteByte(uint16_t addr,uint8_t data)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
int err=0;
i2c_master_start(cmd);
i2c_master_write_byte(cmd, 0xA0 | 0, ACK_CHECK_EN);// Device addressing + read/write selection
i2c_master_write_byte(cmd, (uint8_t)((addr >> 8) & 0xFF), ACK_CHECK_EN);
i2c_master_write_byte(cmd, (uint8_t)(addr & 0xFF), ACK_CHECK_EN);
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
i2c_master_stop(cmd);
i2c_master_cmd_begin(I2C_NUM_1, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
In the file bsp_ds1307.h, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-12 LCKFB-lp first version
*/
#ifndef _BSP_DS1307_H_
#define _BSP_DS1307_H_
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "freertos/queue.h"
#include <inttypes.h>
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "rom/ets_sys.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
#define GPIO_SCL 7
#define GPIO_SDA 8
typedef struct _RTC_TIME_STRUCT_ {
unsigned char sec;
unsigned char min;
unsigned char hour;
unsigned char week;
unsigned char date;
unsigned char month;
unsigned char year;
}_time_struct_;
extern _time_struct_ RTC_Time;
void DS1307_GPIO_Init(void);// Pin initialization
unsigned char Write1307(unsigned char add,unsigned char dat);// Write one byte
unsigned char Read1307(unsigned char add);// Read one byte
void Set_RTC_Time(uint8_t year,uint8_t month,uint8_t date,uint8_t week,uint8_t hour,uint8_t min,uint8_t sec);// Set the initial time
void Get_RTC_Time(void);// Get the RTC time
uint8_t AT24CXX_ReadByte(uint16_t addr);
void AT24CXX_WriteByte(uint16_t addr,uint8_t data);
#endif2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Porting Verification
In the main function of your project, write the following code.
/*
* LCSC-Openkits (LCKFB) software and hardware materials and related expansion board software and hardware materials are all open source on the official website.
* Dev board official website: www.lckfb.com
* Technical support resides on the forum; any technical questions are welcome for exchange and learning at any time.
* LCKFB Forum: club.szlcsc.com
* Follow our Bilibili account: [LCSC-Openkits (LCKFB)] to keep up with our latest updates!
* We do not make money by selling boards; we take cultivating engineers as our mission.
* Change Logs:
* Date Author Notes
* 2024-01-12 LCKFB-lp first version
*/
#include <stdio.h>
#include "bsp_ds1307.h"
#include "string.h"
#include "esp_private/esp_task_wdt.h"
#include "esp_private/esp_task_wdt_impl.h"
int app_main(void)
{
esp_task_wdt_deinit();
DS1307_GPIO_Init();
/*
After power-on, we read the address 0x10 in the AT24C32 data storage chip.
If the read data is 0x77, it means we have already set the time; otherwise, we have not, and we execute the time-setting routine.
*/
if( AT24CXX_ReadByte(0x10) != 0x77)
{
AT24CXX_WriteByte(0x10,0x77);
Set_RTC_Time(24, 1, 12, 5, 15, 36, 0); // Only used when setting the time on first power-on
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("RTC Demo Start....\r\n");
while(1)
{
Get_RTC_Time();// Get the time
printf("%d-%d-%d-Weekday %d\r\n", RTC_Time.year,RTC_Time.month,RTC_Time.date,RTC_Time.week);
printf("%d:%d:%d\r\n",RTC_Time.hour,RTC_Time.min,RTC_Time.sec);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
Power-on behavior:
After disconnecting and reconnecting the dev board, you will find the time is continuous, which shows that the RTC was still counting while the dev board was disconnected.
Driver code:
File Download
📌 Materials Download Center (Click to Jump)
📌 In the Materials Download Center -> Module Porting Materials Download, inside the compressed package of this chapter.