esp32 操作DS1307时钟芯片

2024-03-02 06:20

本文主要是介绍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,即时钟空间的开头。
在这里插入图片描述

  • 在初次上电的时候(指初次装上纽扣电池),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小时制展开。
    在这里插入图片描述

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 周五
在这里插入图片描述发送的字节依次为:设备地址0x68,寄存器地址00,接下来7个字节是要设置进00h-06h这7个寄存器的值。

读取时钟
1.先发送一个数据00,将读取指针只想寄存器0.这个操作在数据手册有说。
在这里插入图片描述2.然后连续读取出数据

在这里插入图片描述## 赋上次芯片的driver代码

#include <stdio.h>
#include "esp_log.h"
#include "ds1307_driver.h"
#include "driver/i2c.h"
#include <string.h>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;// 初始化iicint 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 <stdio.h>
#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 操作DS1307时钟芯片的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/765181

相关文章

使用Java将各种数据写入Excel表格的操作示例

《使用Java将各种数据写入Excel表格的操作示例》在数据处理与管理领域,Excel凭借其强大的功能和广泛的应用,成为了数据存储与展示的重要工具,在Java开发过程中,常常需要将不同类型的数据,本文... 目录前言安装免费Java库1. 写入文本、或数值到 Excel单元格2. 写入数组到 Excel表格

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

Python ZIP文件操作技巧详解

《PythonZIP文件操作技巧详解》在数据处理和系统开发中,ZIP文件操作是开发者必须掌握的核心技能,Python标准库提供的zipfile模块以简洁的API和跨平台特性,成为处理ZIP文件的首选... 目录一、ZIP文件操作基础三板斧1.1 创建压缩包1.2 解压操作1.3 文件遍历与信息获取二、进阶技

Java中字符串转时间与时间转字符串的操作详解

《Java中字符串转时间与时间转字符串的操作详解》Java的java.time包提供了强大的日期和时间处理功能,通过DateTimeFormatter可以轻松地在日期时间对象和字符串之间进行转换,下面... 目录一、字符串转时间(一)使用预定义格式(二)自定义格式二、时间转字符串(一)使用预定义格式(二)自

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

Mysql表的简单操作(基本技能)

《Mysql表的简单操作(基本技能)》在数据库中,表的操作主要包括表的创建、查看、修改、删除等,了解如何操作这些表是数据库管理和开发的基本技能,本文给大家介绍Mysql表的简单操作,感兴趣的朋友一起看... 目录3.1 创建表 3.2 查看表结构3.3 修改表3.4 实践案例:修改表在数据库中,表的操作主要

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处