10. I2C
10.1 What is I2C
The IIC (Inter-Integrated Circuit) protocol, also known as the I2C bus, is a serial communication protocol usually used to connect low-speed peripherals. It was developed by Philips (now NXP Semiconductors) in the early 1980s and has now become a standard. The IIC bus only needs two data lines: the Serial Data Line (SDA) and the Serial Clock Line (SCL), which makes it a very simple interface. It is suitable for chip-based communication, such as connecting sensors, memory, or digital signal processors, etc.
In the IIC protocol, there is one master device and multiple slave devices on the bus. The master device controls the communication process on the bus and is responsible for initiating, controlling, and stopping the communication. The slave devices need to wait for requests from the master device to receive or send data. Data exchange between the master and slave devices uses a frame format. Each frame usually contains address, data, and control information. The master device selects the device to communicate with based on the address of the slave device, and the slave device performs corresponding operations according to the control information. The IIC protocol can support multiple slave devices connected to the same master device, providing greater flexibility for system design.
10.2 Hardware Implementation of I2C
The I2C bus typically uses two voltage levels: high level (VH) and low level (VL). The high level is 2.5 V to 5.5 V, and the low level is 0 V to 0.3 V; these voltage level ranges are determined according to the I2C specification.
The I2C bus has different transmission rates available, including Standard Mode (100 kbps), Fast Mode (400 kbps), and High-Speed Mode. The choice of transmission rate depends on the application requirements and the device's capabilities.
To avoid signal conflicts, the microprocessor (MCU) must only drive SDA and SCL low, that is, open-drain output. The open-drain mode is mainly set to protect devices and prevent interference.
- Preventing interference: Multiple devices share the same data line (SDA) and the same clock line (SCL). If push-pull output mode is used, the outputs of multiple devices will be superimposed on the data line, causing signal interference, and in severe cases, damaging devices or causing communication errors. With open-drain output mode, each device's output only has the part that pulls the data line low and will not interfere with each other, thereby improving the reliability and anti-interference ability of the bus.
- Preventing short circuits: In open-drain output mode, since the device's output only has the part that pulls the data line low, even if two or more devices output at the same time, it will not cause a short circuit. With push-pull output mode, when two or more devices output at the same time, a short circuit may form. For example, the master device outputs a high level and the slave device outputs a low level.
Because it is set to open-drain mode, an external pull-up resistor (for example: 10k) needs to be connected to pull the signal up to a high level. Therefore, the SDA (data line) and SCL (clock line) in the I2C bus are usually connected with pull-up resistors to ensure the stability of the logic high level. The resistance value of the pull-up resistor is usually between 2.2 kΩ and 10 kΩ, depending on the capacitive load of the bus and the communication distance.
The maximum cable length and transmission capacity of the I2C bus are limited. In Standard Mode, the maximum cable length is about 1 meter, while in Fast Mode, the maximum cable length is about 0.3 meters. In addition, the bus capacitance on the cable also affects the transmission rate.
10.3 I2C Data Transmission
The I2C protocol uses a bus arbitration mechanism for data transmission. It has only two communication lines, so its data transmission is based on the clock signal. The clock is generated by the master device and controls the data transmission rate. Data is sent and received by the master device, but its exchange is realized through the acknowledgment of the slave device. The following are several important timings of the IIC bus: Start signal: When SCL is at a high level, the SDA level transitions from high to low, indicating the start of a communication.
void IIC_Start(void)
{
SDA_OUT(); // Set SDA as output mode
SDA(1);
SCL(1);
delay_us(5);
SDA(0);
delay_us(5);
SCL(0);
delay_us(5);
}2
3
4
5
6
7
8
9
10
11
Stop signal: When SCL is at a high level, the SDA level transitions from low to high, indicating the end of this communication. After sending the stop signal, the master device cannot send any more data to the slave device unless it sends a start signal again.
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_us(5);
SDA(1);
delay_us(5);
}2
3
4
5
6
7
8
9
10
11
Data transmission: The master and slave devices transmit data, which can be one or more bytes of data. Sending and receiving are both based on address selection.
// Send one byte
void IIC_Send_Byte(unsigned char dat)
{
int i = 0;
SDA_OUT();
SCL(0);
for( i = 0; i < 8; i++ )
{
SDA( (dat & 0x80) >> 7 );
delay_us(1);
SCL(1);
delay_us(5);
SCL(0);
delay_us(5);
dat<<=1;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Read one byte
unsigned char IIC_Read_Byte(void)
{
unsigned char i,receive=0;
SDA_IN(); // Set SDA as input
for(i=0;i<8;i++ )
{
SCL(0);
delay_us(5);
SCL(1);
delay_us(5);
receive<<=1;
if( SDA_GET() == 1 )
{
receive |= 1;
}
}
SCL(0);
return receive;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
I2C also provides an acknowledgment mechanism called "ACK/NACK". If a device receives data, it will send an acknowledgment signal by pulling the SDA line low to notify the sender that the data has been received. Conversely, if the data is corrupted or not received, the receiving device will send a non-acknowledgment signal. (Keep SDA high).
void IIC_Send_Ack(void)
{
SDA_OUT();
SCL(0);
SDA(1);
SDA(0);
SCL(1);
delay_us(5);
SCL(0);
SDA(1);
}2
3
4
5
6
7
8
9
10
11
void IIC_Send_Nack(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SDA(1);
SCL(1);
delay_us(5);
SCL(0);
SDA(0);
}2
3
4
5
6
7
8
9
10
11
In the IIC bus, the clock line is controlled by the master device. Each data bit is updated at the clock edge, and the maximum transmission rate depends on the slowest device on the bus. Generally speaking, the communication rate of the IIC bus is relatively slow, usually in the range of several hundred kbps. If a higher transmission rate is required, other communication protocols such as the SPI protocol and CAN protocol can be used.
10.4 I2C Communication Flow
The I2C communication flow proceeds according to the following steps:
- The master sends a start signal to the bus.
- The master sends the device address to communicate with and the read/write bit (R/W) to the bus.
- After receiving the address, the device sends an acknowledgment signal. After receiving the acknowledgment signal, the master sends data or continues to send the address.
- After receiving the data, the device sends an acknowledgment signal. After receiving the acknowledgment signal, the master can continue to send data or stop the communication.
- The master sends a stop signal to the bus.
10.5 IIC Basic Parameters
- Speed: The I2C bus has two transmission modes: Standard Mode (100 kbit/s) and Fast Mode (400 kbit/s). There are also faster extended modes and high-speed modes available.
- Device address: Each device has a unique 7-bit or 10-bit address, and the device to communicate with can be selected through the address.
- Bus status: The I2C bus has five states: idle state, start signal, stop signal, acknowledgment signal, and data transmission.
- Data format: The I2C bus has two data formats: standard format and fast format. The standard format is an 8-bit data byte plus a 1-bit ack/nack bit, and the fast format allows two bytes to be transmitted at the same time. Since the SCL and SDA lines are bidirectional, they may also have level errors due to external reasons (such as capacitance in the circuit), which may cause communication errors. Therefore, in the IIC bus, pull-up resistors are usually used to ensure that the signal lines are at a high level in the idle state.
10.6 Software I2C and Hardware I2C
The I2C protocol can be implemented through software or hardware. The difference between the two methods lies in the implementation method and the hardware resources required.
10.6.1 Software I2C
Software I2C refers to implementing the I2C communication protocol by writing code in a program. It uses General Purpose Input/Output (GPIO) pins to simulate the data line (SDA) and clock line (SCL) of I2C, and transmits data and generates timing signals by controlling the level changes of the pins through software. Compared with hardware I2C, the advantage of software I2C is that it does not require specific hardware support and can be implemented on any microcontroller that supports GPIO functions. It uses the general-purpose IO pins of the microcontroller to implement the I2C communication protocol. The implementation of software I2C simulates the master and slave devices of I2C through programming. By reading and writing the status of GPIO pins bit by bit, and performing corresponding operations according to the timing requirements of the I2C protocol, data transmission and communication are realized. Software I2C has high flexibility and can be customized and extended according to application needs. It can handle multiple slave devices and supports a multi-master environment. Therefore, software I2C is widely used in resource-constrained MCU systems, especially in applications that need to communicate with multiple external devices. Although the performance of software I2C is lower than that of hardware I2C, software I2C is an economical and practical solution in scenarios with low-speed communication and simple communication needs.
10.6.2 Hardware I2C
Hardware I2C refers to handling the I2C communication protocol through a dedicated hardware module. Most modern microcontrollers and some external devices have integrated hardware I2C modules. These hardware modules are responsible for handling the details of I2C communication, including generating correct timing signals, automatically handling signal conflicts, data transmission, and error detection. You can directly use the hardware pins for connection without writing timing code. Using hardware I2C is usually relatively simple, and developers do not need to write complex code to handle the details of the communication protocol. The hardware module can be directly connected to external devices, and data and clock are transmitted through dedicated pins, thereby achieving efficient and reliable communication. When choosing between software I2C and hardware I2C, you need to consider the application requirements and hardware resources. Software I2C is suitable for resource-constrained systems and can be implemented on any microcontroller that supports GPIO, but its performance is relatively low. Hardware I2C usually has better performance, but requires hardware support and may occupy some specific pin resources.
10.6.3 Advantages and Disadvantages of IIC
10.6.3.1 Advantages
Bidirectional transmission: The I2C bus supports bidirectional transmission. Data between the master device and slave devices can be transmitted simultaneously through the SDA line, saving bus resources. System integration: The I2C bus can be quickly integrated into chips, reducing the logical complexity of system implementation and improving design efficiency. Multi-device sharing: The I2C bus can realize communication between multiple devices and the master controller through address transmission, allowing multiple devices to share the bus and interact directly. High reliability: The I2C bus uses logical levels instead of electrical signals to represent data transmission, providing higher transmission reliability.
10.6.3.2 Disadvantages
Limited bandwidth: The transmission speed of the I2C bus is limited to 400 kbps. Compared with the SPI bus and CAN bus, the bandwidth is relatively low. Strict timing requirements: I2C bus data transmission needs to strictly follow timing requirements, especially during high-speed transmission. Timing is susceptible to interference, causing communication failures. Limited maximum cable length: Although the I2C bus can extend the bus length through repeaters, due to signal line interference, signal attenuation, and timing requirements, the maximum cable length is generally limited to 1-2 meters. In summary, the I2C bus has advantages such as bidirectional transmission, system integration, and multi-device sharing, but it also has disadvantages such as relatively low transmission speed, strict timing requirements, and limited maximum cable length.
10.7 I2C Introduction of the ESP32-S3
The ESP32-S3 has two hardware I2C controllers (also called ports), responsible for handling communication on the two I2C buses. Each I2C controller can run as a master or a slave. The I2C interface of the ESP32 can be configured as master mode or slave mode, and devices on the I2C bus can be controlled through a simple API.
10.8 Applications of I2C
We can look at the IIC-related functions to get a basic understanding of IIC applications.
/*
The IIC communication sequence is divided into 3 parts: [Start part] [Timing part] [End part]
[Start part] related functions:
void IIC_GPIO_Init(void);
[Timing part] related functions:
i2c_cmd_handle_t i2c_cmd_link_create(void);
esp_err_t i2c_master_start(i2c_cmd_handle_t cmd_handle);
esp_err_t i2c_master_stop(i2c_cmd_handle_t cmd_handle);
esp_err_t i2c_master_write_byte(i2c_cmd_handle_t cmd_handle, uint8_t data, bool ack_en);
esp_err_t i2c_master_read_byte(i2c_cmd_handle_t cmd_handle, uint8_t *data, i2c_ack_type_t ack);
[End part] related functions:
esp_err_t i2c_master_cmd_begin(i2c_port_t i2c_num, i2c_cmd_handle_t cmd_handle, TickType_t ticks_to_wait);
void i2c_cmd_link_delete(i2c_cmd_handle_t cmd_handle);
*/2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
10.8.1 Initialize the I2C Interface
#define GPIO_SCL 7 // IIC clock pin
#define GPIO_SDA 8 // IIC data pin
#define IIC_NUM I2C_NUM_1 // IIC hardware 1
#define ACK_CHECK_EN 0x1 /*!< I2C master will [check] the acknowledgment */
#define ACK_CHECK_DIS 0x0 /*!< I2C master will [not check] the acknowledgment */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master does not need a transmit buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master does not need a receive buffer */
/******************************************************************
* Function Name: IIC_GPIO_Init
* Description: Initialize IIC
* Parameters: None
* Return: None
* Author: LC
* Note: None
******************************************************************/
void IIC_GPIO_Init()
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER, // Set as master
.sda_io_num = GPIO_SDA, // SDA pin setting
.sda_pullup_en = GPIO_PULLUP_ENABLE, // Enable SDA pin pull-up resistor
.scl_io_num = GPIO_SCL, // SCL pin setting
.scl_pullup_en = GPIO_PULLUP_ENABLE, // Enable SCL pin pull-up resistor
.master.clk_speed = 100000, // Use 100KHz clock frequency
// .clk_flags = 0, /* Optional, this option is used to select the clock source */
};
esp_err_t err = i2c_param_config(IIC_NUM, &conf); // Apply the configuration of the conf structure to IIC_NUM
}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
This part of the code defines a structure conf of type i2c_config_t and assigns values to its members. The structure members are parsed as follows:
conf.mode: I2C working mode. Here it is set toI2C_MODE_MASTER, indicating master mode. There is also another optionI2C_MODE_SLAVEindicating slave mode.conf.sda_io_num: SDA pin number.conf.sda_pullup_en: Whether to enable the internal pull-up resistor for the SDA pin. Here it is set toGPIO_PULLUP_ENABLE, enabling the internal pull-up to avoid floating.conf.scl_io_num: SCL pin number.conf.scl_pullup_en: Whether to enable the internal pull-up resistor for the SCL pin. Here it is set toGPIO_PULLUP_ENABLE, enabling the internal pull-up to avoid floating.conf.master.clk_speed: The clock speed of I2C when working in master mode. Here it is set to 100000, that is, 100 kHz, which is the common speed of I2C.
10.8.2 Install the I2C Driver
esp_err_t i2c_driver_install(i2c_port_t i2c_num, i2c_mode_t mode, size_t rx_buf_len, size_t tx_buf_len, int intr_flags)Call the i2c_driver_install() function to install the I2C driver for the specified I2C port number. The parameters are parsed as follows:
- i2c_num: I2C bus port number, of type
i2c_port_t. Available parameters are I2C_NUM_0, I2C_NUM_1. - mode: I2C working mode, including I2C_MODE_MASTER (master mode), I2C_MODE_SLAVE (slave mode), and I2C_MODE_MASTER_SLAVE (master-slave mode), of type
i2c_mode_t. - rx_buf_len: I2C receive buffer length, in bytes. Only used in slave mode. The buffer size must be greater than 0. Here the constant
I2C_MASTER_RX_BUF_DISABLEis used to indicate that the receive buffer is disabled. - tx_buf_len: I2C transmit buffer length, in bytes. Only used in slave mode. The buffer size must be greater than 0. Here the constant
I2C_MASTER_TX_BUF_DISABLEis used to indicate that the transmit buffer is disabled. - intr_flags: I2C driver interrupt flags, used to control whether the I2C interrupt handler is supported. Here the constant 0 is used to indicate that interrupts are not used. After calling this function, the I2C driver will start, so that data can be read from or written to devices on the I2C bus. Example:
// Register the I2C service, i.e., enable it
i2c_driver_install(IIC_NUM, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);2
10.8.3 Read and Write Operations of I2C
Before performing I2C read and write operations, you must create an i2c_cmd_handle_t parameter, and then add a series of commands according to your needs. For example, the following code first creates a cmd parameter, then adds a start command, a write command, and a stop command. Finally, the i2c_master_cmd_begin function is used to execute this series of commands. The read operation is similar.
unsigned char dat;
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // Create and initialize an IIC command list and return a command list handle.
i2c_master_start(cmd); // Start signal
i2c_master_write_byte(cmd, 0xD0, ACK_CHECK_EN); // Write one byte
i2c_master_write_byte(cmd, 0x00, ACK_CHECK_EN); // Write one byte
i2c_master_start(cmd); // Start signal
i2c_master_write_byte(cmd, 0xD1, ACK_CHECK_EN); // Write one byte
i2c_master_read_byte(cmd, &dat, ACK_CHECK_EN); // Read one byte and return the read byte.
i2c_master_stop(cmd); // Stop signal
esp_err_t ret = i2c_master_cmd_begin(IIC_NUM, cmd, 1000 / portTICK_PERIOD_MS); // In master mode, send all queued commands on the I2C command list.
i2c_cmd_link_delete(cmd); // Release the IIC command list2
3
4
5
6
7
8
9
10
11
12
13
14
15
The following will introduce the functions and parameters one by one.
i2c_cmd_handle_t cmd = i2c_cmd_link_create(); This function is used to create a new I2C command link and return its handle. When sending or receiving I2C data, you need to first establish a command link and then add corresponding commands.i2c_master_start(cmd); Adds a start signal to the I2C command link. The function parameters are as follows:
- cmd: The I2C command link handle to add to.
i2c_master_write_byte(cmd, (DEVICE_ADDR << 1) | WRITE_BIT, ACK_CHECK_EN); Adds a one-byte write operation to the I²C command link. The function parameters are as follows:
cmd: The I2C command link handle to add to.- (DEVICE_ADDR << 1) | WRITE_BIT: The byte to be written. Here the device address is written (shifted left by 1 bit) and the write flag bit is added.
- ACK_CHECK_EN: Indicates whether to check the slave's acknowledgment (ACK). Here ACK_CHECK_EN is used, indicating that an acknowledgment is required.
i2c_master_stop(cmd); Adds a stop signal to the I²C command link. The function parameters are as follows:
- cmd: The I2C command link handle to add to.
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);Executes the operations previously added to the I2C command link. The function parameters are as follows:
- I2C_MASTER_NUM: The I2C port number to operate on.
- cmd: The I2C command link handle to add to.
- 1000 / portTICK_RATE_MS: Timeout, in OS ticks. Here 1000 / portTICK_RATE_MS is used to indicate a timeout of 1000 ms, that is, 1 second.
i2c_cmd_link_delete(cmd);Deletes the I2C command link. After executing the command link, you need to call this function to release resources. The function parameters are as follows:
- cmd: The I2C command link handle to delete.
In fact, there are other functions and parameters that can be used during I2C communication. For example, when reading data, you can use the i2c_master_read_byte() and i2c_master_read() functions. These functions allow you to read one byte or a certain length of data respectively. In addition, you can use the i2c_master_write() function to write multiple bytes of data at once. Also note that in the above example, DEVICE_ADDR, WRITE_BIT, and ACK_CHECK_EN are undefined constants.
10.9 I2C Verification
Use to test. In the file bsp_ds1307.c, write the following code.
/*
* LCSC-Openkits(LCKFB) development board hardware and software materials and related expansion board hardware and software materials are all open source on the official website
* Development board official website: www.lckfb.com
* Technical support is resident on the forum. Any technical questions are welcome for communication and learning at any time
* LCKFB Forum: club.szlcsc.com
* Follow the Bilibili account: [LCSC-Openkits], to keep up with our latest updates!
* Not relying on selling boards for profit, taking the training of Chinese engineers as our responsibility
* 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] the acknowledgment */
#define ACK_CHECK_DIS 0x0 /*!< I2C master will [not check] the acknowledgment */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master does not need a transmit buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master does not need a receive buffer */
/******************************************************************
* Function Name: DS1307_GPIO_Init
* Description: Initialize the IIC pins
* Parameters: None
* Return: None
* Author: LC
* Note: 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
* Description: Write dat data to address add of DS1307
* Parameters: add = register address to write dat = data to write
* Return: 0 = write successful 1 = no acknowledgment for device address 2 = no acknowledgment for register address
* Author: LC
* Note: Device address = 0xD0
******************************************************************/
unsigned char Write1307(unsigned char add,unsigned char dat)
{
unsigned char temp;
/* Decimal to BCD code */
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
* Description: Read time data from DS1307
* Parameters: add = register address to read
* Return: 255 = read failed other = read successful
* Author: LC
* Note: 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 */
temp=dat/16;
dat=dat%16;
dat=dat+temp*10;
return(dat);
}
/******************************************************************
* Function Name: get_RTC_time
* Description: Get the time of DS1307
* Parameters: None
* Return: None
* Author: LC
* Note: 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
* Description: Set the RTC time
* Parameters: year = year range 00-99 (last two digits of the year)
* month = month range 01-12
* date = date range 01-31
* week = day of the week range 01-07
* hour = hour range 01-12 or 00-23
* min = minute range 00-59
* sec = second range 00-59
* Return:
* Author: LC
* Note: For example, to set the 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 day of the week
Write1307(0x04,date); // Set date
Write1307(0x05,month); // Set month
Write1307(0x06,year); // Set year
}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
In the file bsp_ds1307.h, write the following code.
/*
* LCSC-Openkits(LCKFB) development board hardware and software materials and related expansion board hardware and software materials are all open source on the official website
* Development board official website: www.lckfb.com
* Technical support is resident on the forum. Any technical questions are welcome for communication and learning at any time
* LCKFB Forum: club.szlcsc.com
* Follow the Bilibili account: [LCSC-Openkits], to keep up with our latest updates!
* Not relying on selling boards for profit, taking the training of Chinese engineers as our responsibility
* 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
#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
In main.c, write the following.
/*
* LCSC-Openkits(LCKFB) development board hardware and software materials and related expansion board hardware and software materials are all open source on the official website
* Development board official website: www.lckfb.com
* Technical support is resident on the forum. Any technical questions are welcome for communication and learning at any time
* LCKFB Forum: club.szlcsc.com
* Follow the Bilibili account: [LCSC-Openkits], to keep up with our latest updates!
* Not relying on selling boards for profit, taking the training of Chinese engineers as our responsibility
* 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)
{
DS1307_GPIO_Init();
Set_RTC_Time(24, 1, 12, 5, 15, 36, 0); // Only used when setting the time for the first power-on
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
printf("RTC Demo Start....\r\n");
while(1)
{
Get_RTC_Time(); // Get the time
printf("%d-%d-%d-week %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
Power-on phenomenon: Disconnect the development board. After reconnecting, the time is found to be discontinuous, which indicates that the RTC was still counting when the development board was disconnected.