esp32 操作DS1307时钟芯片

2024-01-27 17:36

本文主要是介绍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/650997

相关文章

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

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

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

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

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Redis中管道操作pipeline的实现

《Redis中管道操作pipeline的实现》RedisPipeline是一种优化客户端与服务器通信的技术,通过批量发送和接收命令减少网络往返次数,提高命令执行效率,本文就来介绍一下Redis中管道操... 目录什么是pipeline场景一:我要向Redis新增大批量的数据分批处理事务( MULTI/EXE

使用Python高效获取网络数据的操作指南

《使用Python高效获取网络数据的操作指南》网络爬虫是一种自动化程序,用于访问和提取网站上的数据,Python是进行网络爬虫开发的理想语言,拥有丰富的库和工具,使得编写和维护爬虫变得简单高效,本文将... 目录网络爬虫的基本概念常用库介绍安装库Requests和BeautifulSoup爬虫开发发送请求解

Oracle存储过程里操作BLOB的字节数据的办法

《Oracle存储过程里操作BLOB的字节数据的办法》该篇文章介绍了如何在Oracle存储过程中操作BLOB的字节数据,作者研究了如何获取BLOB的字节长度、如何使用DBMS_LOB包进行BLOB操作... 目录一、缘由二、办法2.1 基本操作2.2 DBMS_LOB包2.3 字节级操作与RAW数据类型2.

JDK多版本共存并自由切换的操作指南(本文为JDK8和JDK17)

《JDK多版本共存并自由切换的操作指南(本文为JDK8和JDK17)》本文介绍了如何在Windows系统上配置多版本JDK(以JDK8和JDK17为例),并通过图文结合的方式给大家讲解了详细步骤,具有... 目录第一步 下载安装JDK第二步 配置环境变量第三步 切换JDK版本并验证可能遇到的问题前提:公司常