esp32 操作DS1307时钟芯片

电气参数摘要

  • 有VCC供电,IIC活动状态是1.5mA,待机状态200μA,电池电流5nA(MAX=50nA)
  • 无VCC供电的时候,电池电流,300nA(时钟运行),10nA(时钟停止)
  • 供电电压是4.5-5.5V,不支持3.3V
  • IIC频率最大400kHZ。
  • 因为ESP32不支持5V电压,但是DS1307必须用5V供电,因此在IIC上拉电阻的位置,必须上拉到3.3V。否则直接给ESP32的IO灌5V可能会烧掉。可以使用ESP32内部的IO上拉,然后去掉外部的上拉就行。

IIC的通信

  • 访问是通过实施启动条件,并提供设备识别代码,后跟寄存器地址而获得的。可以按顺序访问后续寄存器,直到执行停止条件为止。
  • 芯片iic地址是0x68
  • 配置寄存器,先发送设备地址,发送寄存器地址(比如0),然后发送寄存器的值。可以一次性发送多个字节,芯片会自动偏移寄存器地址。
  • 读取寄存器,先发送寄存器地址,然后读取。支持连续读取多个寄存器。

寄存器

  • RTC寄存器位于地址00h至07h的位置。
  • RAM寄存器位于地址08h至3Fh的位置。

在多字节访问期间,当地址指针达到3Fh,即RAM空间的末尾时,它会环绕到位置00h,即时钟空间的开头。
esp32 操作DS1307时钟芯片_第1张图片

  • 在初次上电的时候(指初次装上纽扣电池),CH位是置1的,表示振荡器停止,计时功能处于停止状态。这时候纽扣电池的耗电量位10nA。
  • 所以在初次使用的时候,需要对CH位清零,一般这个清零操作会在设置当前时间到DS1307时同时完成。
  • 当CH位置0后,断开主电,RTC也会继续运行,这时候纽扣电池的耗电量典型值为300nA(无方波输出时)。

计算

  1. 芯片将“年月日时分秒周”存放到地址00-06这7个寄存器里面。每个寄存器相应bit对应的含义,看寄存器列表。
  2. 读取秒的寄存器是00h。先要读取出10倍数的秒(也就是十位数),对应BIT4~bit6.
    然后读取个位数的秒数,BIT0~BIT3.
    在这里插入图片描述
    比如读取到寄存器值为0x59,则对应二进制为00101 1001b。则bit4~bit6=5 ,BIT0~BIT3= 9最终为5*10+9=59秒。
    这个寄存器的CH位是时钟启停控制bit。
    3.比如读小时,小时在芯片里面有12小时表示法和24小时表示法。具体看BIT6。
    当bit6=1,则剩余的bit按照12小时制展开。
    当bit6=0,则剩余的bit按照24小时制展开。
    esp32 操作DS1307时钟芯片_第2张图片

DS1307上的RAM

这个RAM是留给用户使用的存储空间,RTC不会用到这部分RAM

DS1307上的RAM(随机存储器)用于存储临时数据,用户自定义的设置以及其他需要在断电时保持的信息。以下是DS1307上RAM的主要用途:

存储用户数据: 用户可以将自定义数据存储在DS1307的RAM中。这可以包括配置参数、计数器值、标志位等。因为这部分RAM是带电池支持的,所以即使在主电源断电时,这些数据也会被保持。

保存配置信息: DS1307的RAM可以用于存储与实时时钟(RTC)和其他功能相关的配置信息。这些配置信息可能包括时钟格式(12小时或24小时制)、日期格式、方波输出频率等。

临时存储: RAM还可用于存储临时性的运行时数据。例如,当进行时钟校准或其他运行时操作时,可能需要在RAM中存储一些中间数据。

断电备份: 由于RAM是带电池支持的,所以它提供了断电备份的功能。即使主电源断电,RAM中的数据仍然会被保存,确保在电源重新连接时可以恢复先前的状态。

总的来说,DS1307上的RAM为用户提供了一块持久存储区域,允许在断电时保留关键的信息。这在需要在系统重新上电时恢复先前状态或保留特定配置和数据时非常有用。

操作时序

设置时钟,比如设置时钟为2024-01-26 10:37:10 周五
esp32 操作DS1307时钟芯片_第3张图片发送的字节依次为:设备地址0x68,寄存器地址00,接下来7个字节是要设置进00h-06h这7个寄存器的值。

读取时钟
1.先发送一个数据00,将读取指针只想寄存器0.这个操作在数据手册有说。
esp32 操作DS1307时钟芯片_第4张图片2.然后连续读取出数据

esp32 操作DS1307时钟芯片_第5张图片## 赋上次芯片的driver代码

#include 
#include "esp_log.h"
#include "ds1307_driver.h"
#include "driver/i2c.h"
#include 

static const char *TAG = "ds1307-driver";

#define I2C_MASTER_SCL_IO CONFIG_I2C_MASTER_SCL /*!< GPIO number used for I2C master clock */
#define I2C_MASTER_SDA_IO CONFIG_I2C_MASTER_SDA /*!< GPIO number used for I2C master data  */
#define I2C_MASTER_NUM 0                        /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
#define I2C_MASTER_FREQ_HZ 100000               /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0             /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0             /*!< I2C master doesn't need buffer */
#define I2C_MASTER_TIMEOUT_MS 1000

#define DS1307_I2C_ADDR 0x68 /*!< Slave address of the MPU9250 sensor */

RTC_time_typedef time;

esp_err_t ds1307_init(void)
{
    int ret;

    // 初始化iic
    int i2c_master_port = I2C_MASTER_NUM;

    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_MASTER_SDA_IO,
        .scl_io_num = I2C_MASTER_SCL_IO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_MASTER_FREQ_HZ,
    };

    i2c_param_config(i2c_master_port, &conf);

    ret = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);

    ESP_LOGI(TAG, "I2C initialized successfully");

    return ret;
}

esp_err_t ds1307_read_time(date_time_t *p_time)
{
    int ret;
    uint8_t write_buf[8] = {0};
    uint8_t *p = (uint8_t *)p_time;

    // 1.先要发一个字节(write),值为0,
    write_buf[0] = 0;
    ret = i2c_master_write_to_device(I2C_MASTER_NUM, DS1307_I2C_ADDR, write_buf, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);

    vTaskDelay(20 / portTICK_PERIOD_MS);

    // 开始读取数据
    ret = i2c_master_read_from_device(I2C_MASTER_NUM, DS1307_I2C_ADDR, (uint8_t *)&time, 7, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);

    ESP_LOGI(TAG, "get raw data:%x,%x,%x,%x,%x,%x,%x,", *(p + 0), *(p + 1), *(p + 2), *(p + 03), *(p + 04), *(p + 05), *(p + 06));

    p_time->second = time.seconds.ten_sec * 10 + time.seconds.seconds;
    p_time->minute = time.minutes.ten_min * 10 + time.minutes.minutes;
    p_time->hour = time.hours.ten_hour * 10 + time.hours.hours;
    p_time->week = time.weeks.week;
    p_time->day = time.dates.ten_date * 10 + time.dates.date;
    p_time->month = time.months.ten_month * 10 + time.months.month;
    p_time->year = time.years.ten_year * 10 + time.years.year;

    ESP_LOGI(TAG, "%d-%d-%d %d:%d:%d week=%d", p_time->year, p_time->month, p_time->day, p_time->hour, p_time->minute, p_time->second, p_time->week);

    return ret;
}

/**
 * @brief 设置芯片的时间
 */
esp_err_t ds1307_set_time(date_time_t datetime)
{
    int ret;
    RTC_time_typedef time;
    uint8_t write_buf[9] = {0};
    uint8_t *p = (uint8_t *)&time;

    time.years.ten_year = datetime.year / 10;
    time.years.year = datetime.year % 10;
    time.months.ten_month = datetime.month / 10;
    time.months.month = datetime.month % 10;
    time.dates.ten_date = datetime.day / 10;
    time.dates.date = datetime.day % 10;
    time.weeks.week = datetime.week;
    time.hours.ten_hour = datetime.hour / 10;
    time.hours.hours = datetime.hour % 10;
    time.minutes.ten_min = datetime.minute / 10;
    time.minutes.minutes = datetime.minute % 10;
    time.seconds.ten_sec = datetime.second / 10;
    time.seconds.seconds = datetime.second % 10;
    time.seconds.ch = 0;

    ESP_LOGI(TAG, "set raw data:%x,%x,%x,%x,%x,%x,%x,", *(p + 0), *(p + 1), *(p + 2), *(p + 03), *(p + 04), *(p + 05), *(p + 06));

    memcpy(write_buf + 1, p, 7);

    ret = i2c_master_write_to_device(I2C_MASTER_NUM, DS1307_I2C_ADDR, write_buf, 8, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);

    return ret;
}

头文件

#ifndef __DS1307_H_
#define __DS1307_H_

#include "driver/i2c.h"

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t seconds : 4;
            uint8_t ten_sec : 3;
            uint8_t ch : 1;
        };
    };
} second_data_TypeDef; // 秒

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t minutes : 4;
            uint8_t ten_min : 3;
            uint8_t bit7 : 1;
        };
    };
} minutes_data_TypeDef; // 分

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t hours : 4;
            uint8_t ten_hour : 2;
            uint8_t jinzhi : 1;
            uint8_t : 1;
        };
    };
} hours_data_TypeDef; // 时

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t week : 3;
            uint8_t : 5;
        };
    };
} weeks_data_TypeDef; // 周

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t date : 4;
            uint8_t ten_date : 2;
            uint8_t : 2;
        };
    };
} dates_data_TypeDef; // 日

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t month : 4;
            uint8_t ten_month : 1;
            uint8_t : 3;
        };
    };
} months_data_TypeDef; // 月

typedef struct
{
    union
    {
        uint8_t value;
        struct
        {
            uint8_t year : 4;
            uint8_t ten_year : 4;
        };
    };
} years_data_TypeDef; // 年

typedef struct
{
    second_data_TypeDef seconds;
    minutes_data_TypeDef minutes;
    hours_data_TypeDef hours;
    weeks_data_TypeDef weeks;
    dates_data_TypeDef dates;
    months_data_TypeDef months;
    years_data_TypeDef years;
} RTC_time_typedef;

typedef struct
{
    uint16_t year;
    uint16_t month;
    uint16_t day;
    uint8_t week;
    uint16_t hour;
    uint16_t minute;
    uint16_t second;
} date_time_t;

esp_err_t ds1307_init(void);
esp_err_t ds1307_read_time(date_time_t *p_time);
esp_err_t ds1307_set_time(date_time_t datetime);

#endif

main文件

#include 
#include "esp_log.h"
#include "ds1307_driver.h"

static const char *TAG = "i2c_DS1307_main";

void app_main(void)
{
    date_time_t date_time={
        .year = 24,
        .month = 1,
        .day = 26,
        .week = 5,
        .hour = 10,
        .minute = 37,
        .second = 10,
    },date_time_now;

    ESP_ERROR_CHECK(ds1307_init());
    

    /* Read the MPU9250 WHO_AM_I register, on power up the register should have the value 0x71 */
    ESP_ERROR_CHECK(ds1307_set_time(date_time));
    ESP_LOGI(TAG, "set successfully");

    vTaskDelay(3000/portTICK_PERIOD_MS);

    while(1)
    {
        ds1307_read_time(&date_time_now);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }

}


程序小结:

  1. 这个芯片读取数据没有校验位,因此在操作的时候,如果太快,还是比较容易出现数据不对。因此要想办法校验数据正确性。
  2. 可以多次读取,然后判断值的有效性

你可能感兴趣的:(单片机,嵌入式硬件,esp32)