目录

一、模块简介

DS3231时钟芯片结构原理

引脚图

内部结构图

DS3231典型应用电路

DS3231时钟芯片结构

二、与stm32通信

1、配置IO

2、初始化与函数

3、主函数调用

4、使用


源码下载
一、模块简介

DS3231是一款高精度I2C实时时钟器件,具有集成的温度补偿晶体振荡器。该器件包含电池输入端,断开主电源时仍可保持精确计时。集成的晶体振荡器可提高器件的长期精确度。DS3231的寄存器能保存秒、分、时、星期、日期、月、年和闹钟设置等信息。少于31天的月份,可自动调整月末日期,包括闰年补偿。时钟的工作格式为24小时或带AM/PM指示的12小时格式。DS3231提供两个可编程日历闹钟和一路可编程方波输出。DS3231与单片机通过I2C双向串行总线传输地址与数据。

DS3231时钟芯片结构原理

DS3231是一款高精度I2C实时时钟(RTC)器件,具有集成的温度补偿晶体振荡器(TCXO)。该器件包含电池输入端,断开主电源时仍可保持精确计时。集成的晶体振荡器可提高器件的长期精确度。DS3231的寄存器能保存秒、分、时、星期、日期、月、年和闹钟设置等信息。少于31天的月份,可自动调整月末日期,包括闰年补偿。时钟的工作格式为24小时或带AM/PM指示的12小时格式。DS3231提供两个可编程日历闹钟和一路可编程方波输出。DS3231与单片机通过I2C双向串行总线传输地址与数据。

引脚图

VCC为电源引脚;

INT/SQW为低电平有效中断或方波输出:是低电平有效复位引脚;

N.C.表示无连接,外部必须接地;

GND为地;

VBAT为备用电源输入;

SDA为串行数据输入输出;

SCL为串行时钟输入。

内部结构图

DS3231典型应用电路

下图为DS3231典型应用电路,图中可看出,DS3231几乎不需要外部元件。

DS3231时钟芯片结构

如下图1所示,DS3231的主要组成部分有8个模块,划分为4个功能组:TCXO、电源控制、按钮复位和RTC。

1. 32 kHz的TCXO

TCXO包括温度传感器、振荡器和控制逻辑。控制器读取片上温度传感器输出,使用查表法确定所需的电容,加上AGE寄存器的老化修正。然后设置电容选择寄存器。仅在温度变化或者用户启动的温度转换完成时,才加载包括AGE寄存器变化的新值。VCC初次上电时就会读取温度值,然后每隔64 s读取一次。

2. DS3231的内部寄存器及功能

DS3231寄存器地址为00h~12h,分别用于存放秒、分、时、星期、日期及闹钟设置信息。在多字节访问期间,如果地址达到RAM空间的结尾12h处,将发生卷绕,此时定位到开始位置即00h单元。DS3231的时间和日历信息通过读取相应的寄存器来设置和初始化。用户辅助缓冲区用于防止内部寄存器更新时可能出现的错误。读取时间和日历寄存器时,用户缓冲区在任何START条件下或者寄存器指针返回到零时与内部寄存器同步。时间信息从这些辅助寄存器读取,此时时钟继续保持运行状态。这样在读操作期间发生主寄存器更新时可以避免重新读取寄存器。以控制寄存器(地址为0EH)为例,可以控制实时时钟、闹钟和方波输出。其各bit定义如下表。

BIT7位:使能振荡器(EOEC)。设定为逻辑0时,启动振荡器。如果设定为逻辑1,在DS3231电源切换至VBAT时,振荡器停止。初次上电时该位清零 (逻辑0) 。当DS3231由VCC供电时,振荡器与EOSC位的状态无关,始终保持工作状态。

BIT6位:电池备份的方波使能(BBSOW)。温度转换不影响内部64 s更新周期。用户启动的温度转换在大约2 ms内不会影响BSY位。CONV位从写入开始直到转换完成一直保持为1,转换完后,CONV和BSY均变为0。在监视用户启动转换状态时,应使用CONV位。

BIT4和BIT3位:频率选择(RS2和RS1),初次上电时,BIT

当设定为逻辑1并且DS3231由VBAT引脚供电时,在没有加载VCC的情况下,该位使能方波输出。当BB-SQW设定为逻辑0时,若VCC降至低于电源故障门限值,则INT/SQW引脚变为高阻抗。初次上电时,该位清零(逻辑0)。

BIT5位:转换温度(CONV)。该位置为1时,强制温度传感器将温度转换成数字,并执行TCXO算法更新振荡器的电容阵列。只在空闲期间有效。状态位BSY=1时,禁止设定转换温度位。用户在强制控制器开始新的TCXO操作之前。应检查状态位BSY。用户启动的

4和BIT3设置为逻辑1。方波使能时用于控制方波输出的频率。RS1、RS2的逻辑值与方波输出频率的关系如表2所列。

BIT2位:中断控制(INTCN)。该位控制INT/SQW信号。INTCN置为0时,INT/SQW引脚输出方波;INTCN置为1时,若计时寄存器与任一个闹钟寄存器相匹配,则会触发INT/SQW信号(如果也使能闹钟的话)。匹配时相应的闹钟标志总是置位,而与INTCN位的状态无关。初次上电时,INTCN位置为逻辑1。

BIT1位:闹钟2中断使能(A2IE)。该位置为逻辑1时,允许状态寄存器中的闹钟2标志位(A2F)触发INT/SQW信号(当INTCN=1时)。当A2IE位置为0或者INTCN置为0时,A2F位不启动中断信号。初次上电时,A2IE位清零(逻辑0)。

BIT0位:闹钟1中断使能(A1IE)。该位置为逻辑1时,允许状态寄存器中的闹钟1标志位(A1F)触发INT/SQW信号(当INTCN=1时)。当A1IE位置为0或者INTCN置为0时,A1F位不启动INT/SQW信号。初次上电时,A1IE位清零(逻辑0)。

3. DS3231的电源控制

电源控制功能由温度补偿电压基准(VPF)和监视VCC电平的比较器电路提供。当VCC高于VPF时,DS3231由VCC供电,当VCC低于VPF但高于VBAT时,DS3231由VCC供电;当VCC低于VPF并低于VBAT时,DS3231由VBAT供电。为保护电池,VBAT首次加到器件时振荡器并不启动,除非加载VCC,或者向器件写入一个有效的I2C地址。典型的振荡器启动时间在1 s以内。在VCC加电后或者有效的I2C地址写入后大约2 s,器件会测量一次温度,并使用计算的修正值校准振荡器。一旦振荡器运行,只要电源(VCC或者VBAT)有效就会一直保持工作状态。器件每隔64 s进行一次温度测量并校准振荡器频率。

4. DS3231的时钟和日历RTC

可以通过读取适当的寄存器字节获得时钟和日历信息。通过写入适当的寄存器字节设定或者初始化时钟和日历数据。时钟和日历寄存器的内容采用二-十进制编码(BCD)格式。DS3231运行于12小时或者24小时模式。小时寄存器的第6位定义为12或24小时模式选择位。该位为高时,选择12小时模式。在12小时模式下,第5位为AM/PM指示位,逻辑高时为PM。

5. DS3231的复位按钮

DS3231具有连接至RST输出引脚的按钮开关功能。若DS3231不在复位周期,会持续监视RST信号的下降沿。如果检测到一个边沿转换,DS3231通过拉低RST完成开关去抖。内部定时器定时结束后,DS3231继续监视RST信号。如果信号依旧保持低电平,DS3231持续监视信号线以检测上升沿。一旦检测到按钮释放,DS3231强制RST为低电平并保持tRST。RST还可用于指示电源故障报警情况。当VCC低于VPF时,产生内部电源故障报警信号,并强制拉低RST引脚。当VCC返回至超过VPF电平时。RST保持低电平大约250 ms(tREC),使供电电源达到稳定。如果在VCC加载时,振荡器不工作,将跳过tREC,RST立刻变为高电平。

二、与stm32通信

模块通过stm32模拟I2C信号通道,接在串口3或者4,下面上源码(串口3为例)

1、配置IO

/********************************************************************************* @file    bsp_i2c_ds3231.h  * @author  兲涳* @version V1.0* @date    2020-11-16* @brief   i2c RTC(DS3231)应用函数bsp******************************************************************************* @attention* *******************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __I2C_DS3231_H
#define __I2C_DS3231_H/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "stdio.h"/* Exported types ------------------------------------------------------------*/
typedef struct
{int hour;int min;int sec;          u32 year;int month;int date;int week;int temperature;
}_calendar_obj;
extern _calendar_obj calendar;  //日历结构体/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/**************************I2C参数定义,I2C1或I2C2*****************************/
#define _I2C1    1
#define _I2C2    0#if _I2C1
#define             DS3231_I2Cx                                I2C1
#define             DS3231_I2C_APBxClock_FUN                   RCC_APB1PeriphClockCmd
#define             DS3231_I2C_CLK                             RCC_APB1Periph_I2C1
#define             DS3231_I2C_GPIO_APBxClock_FUN              RCC_APB2PeriphClockCmd
#define             DS3231_I2C_GPIO_CLK                        RCC_APB2Periph_GPIOC
#define             DS3231_I2C_SCL_PORT                        GPIOC
#define             DS3231_I2C_SCL_PIN                         GPIO_Pin_10
#define             DS3231_I2C_SDA_PORT                        GPIOC
#define             DS3231_I2C_SDA_PIN                         GPIO_Pin_11#elif _I2C2
#define             DS3231_I2Cx                                I2C2
#define             DS3231_I2C_APBxClock_FUN                   RCC_APB1PeriphClockCmd
#define             DS3231_I2C_CLK                             RCC_APB1Periph_I2C2
#define             DS3231_I2C_GPIO_APBxClock_FUN              RCC_APB2PeriphClockCmd
#define             DS3231_I2C_GPIO_CLK                        RCC_APB2Periph_GPIOB
#define             DS3231_I2C_SCL_PORT                        GPIOB
#define             DS3231_I2C_SCL_PIN                         GPIO_Pin_10
#define             DS3231_I2C_SDA_PORT                        GPIOB
#define             DS3231_I2C_SDA_PIN                         GPIO_Pin_11#endif/* STM32 I2C 快速模式 */
#define             I2C_Speed                                                    400000
/* 这个地址只要与STM32外挂的I2C器件地址不一样即可 */
#define                         I2Cx_OWN_ADDRESS7                                            0X0A
/* DS3231 地址定义 */
#define DS3231_ADDRESS                                                                               0xD0   /*等待超时时间*/
#define I2CT_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT         ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))/*信息输出*/
#define DS3231_DEBUG_ON         0#define DS3231_INFO(fmt,arg...)           printf("<<-DS3231-INFO->> "fmt"\n",##arg)
#define DS3231_ERROR(fmt,arg...)          printf("<<-DS3231-ERROR->> "fmt"\n",##arg)
#define DS3231_DEBUG(fmt,arg...)          do{\if(DS3231_DEBUG_ON)\printf("<<-DS3231-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\}while(0)/* DS3231寄存器地址 */#define                           DS3231_SECOND                                                            0x00    //秒
#define                         DS3231_MINUTE                                                    0x01    //分
#define                         DS3231_HOUR                                                      0x02    //时
#define                         DS3231_WEEK                                                      0x03    //星期
#define                         DS3231_DAY                                                       0x04    //日
#define                         DS3231_MONTH                                                     0x05    //月
#define                         DS3231_YEAR                                                      0x06    //年
/* 闹铃1 */
#define                         DS3231_SALARM1ECOND                        0x07    //秒
#define                         DS3231_ALARM1MINUTE                        0x08    //分
#define                         DS3231_ALARM1HOUR                          0x09    //时
#define                         DS3231_ALARM1WEEK                                                0x0A    //星期/日
/* 闹铃2 */
#define                         DS3231_ALARM2MINUTE                                              0x0b    //分
#define                         DS3231_ALARM2HOUR                          0x0c    //时
#define                         DS3231_ALARM2WEEK                          0x0d    //星期/日#define                        DS3231_CONTROL                             0x0e    //控制寄存器
#define                         DS3231_STATUS                              0x0f    //状态寄存器
#define                         BSY                                                              2       //忙
#define                         OSF                                                              7       //振荡器停止标志
#define                         DS3231_XTAL                                                      0x10    //晶体老化寄存器
#define                         DS3231_TEMPERATUREH                                              0x11    //温度寄存器高字节(8位)
#define                         DS3231_TEMPERATUREL                                              0x12    //温度寄存器低字节(高2位)                                                                                /* Exported functions ------------------------------------------------------- */
void I2C_DS3231_Init(void);
uint32_t I2C_DS3231_ByteWrite(u8 WriteAddr, u8 data);
uint8_t I2C_DS3231_DataRead(u8 ReadAddr);
void I2C_WaitDs3231StandbyState(void);
uint8_t BCD_DEC(u8 val);
uint8_t DEC_BCD(u8 val);void I2C_DS3231_SetTime(u8 yea,u8 mon,u8 da,u8 we,u8 hou,u8 min,u8 sec);
void Time_Regulate_Get(_calendar_obj *tm);void I2C_DS3231_getTime(void);
void I2C_DS3231_getTemperature(void);void GregorianDay(_calendar_obj * tm);#endif /* __I2C_DS3231_H *//*********************************************END OF FILE**********************/

2、初始化与函数

/********************************************************************************* @file    bsp_i2c_ds3231.c * @author  兲涳* @version V1.0* @date    2020-11-16* @brief   i2c RTC(DS3231)应用函数bsp******************************************************************************* @attention* *******************************************************************************/  /* Includes ------------------------------------------------------------------*/
#include "bsp_i2c_ds3231.h" /* Private typedef -----------------------------------------------------------*/
_calendar_obj calendar;
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static __IO uint32_t  I2CTimeout = I2CT_LONG_TIMEOUT;
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode);/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/*** @brief  转换成BCD码* @param  无* @retval 无*/
u16 B_BCD(u8 val)
{u8 i,j,k;i=val/10;j=val%10;k=j+(i<<4);return k;
}/*** @brief  I2C I/O配置* @param  无* @retval 无*/
static void I2C_GPIO_Config(void)
{GPIO_InitTypeDef  GPIO_InitStructure; /* 使能与 I2C 有关的时钟 */DS3231_I2C_APBxClock_FUN ( DS3231_I2C_CLK, ENABLE );DS3231_I2C_GPIO_APBxClock_FUN ( DS3231_I2C_GPIO_CLK, ENABLE );/* I2C_SCL、I2C_SDA*/GPIO_InitStructure.GPIO_Pin = DS3231_I2C_SCL_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;           // 开漏复用输出GPIO_Init(DS3231_I2C_SCL_PORT, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = DS3231_I2C_SDA_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;           //  开漏复用输出GPIO_Init(DS3231_I2C_SDA_PORT, &GPIO_InitStructure);
}/*** @brief  I2C 工作模式配置* @param  无* @retval 无*/
static void I2C_Mode_Configu(void)
{I2C_InitTypeDef I2C_InitStructure;/* 通信速率 */I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;/* I2C 配置 */I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;/* 高电平数据稳定,低电平数据变化 SCL 时钟线的占空比 */I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;/* 地址设置 */I2C_InitStructure.I2C_OwnAddress1 = I2Cx_OWN_ADDRESS7;/* 使能应答 */I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;/* I2C的寻址模式 */I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;/* I2C 初始化 */I2C_Init(DS3231_I2Cx, &I2C_InitStructure);/* 使能 I2C */I2C_Cmd(DS3231_I2Cx, ENABLE);
}/*** @brief  I2C 外设(DS3231)初始化* @param  无* @retval 无*/
void I2C_DS3231_Init(void)
{I2C_GPIO_Config(); I2C_Mode_Configu();
}/*** @brief   写一个字节到I2C DS3231中* @param   *      @arg data:要写入的字节*      @arg WriteAddr:写地址 * @retval 返回1,表示写入成功.*/
uint32_t I2C_DS3231_ByteWrite(u8 WriteAddr, u8 data)
{/* 产生 I2C 起始信号 */I2C_GenerateSTART(DS3231_I2Cx, ENABLE);/* 设置超时等待时间 */I2CTimeout = I2CT_FLAG_TIMEOUT;  /* 检测 EV5 事件并清除标志*/while (!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(0);}I2CTimeout = I2CT_FLAG_TIMEOUT;/* 发送 DS3231 设备地址 */I2C_Send7bitAddress(DS3231_I2Cx, DS3231_ADDRESS, I2C_Direction_Transmitter);/* 检测 EV6 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);}/* 发送要写入的 DS3231 内部地址(即 DS3231 内部存储器的地址) */I2C_SendData(DS3231_I2Cx, WriteAddr);I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV8 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);}/* 发送一字节要写入的数据 */I2C_SendData(DS3231_I2Cx, data); I2CTimeout = I2CT_FLAG_TIMEOUT;  /* 检测 EV8 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);}/* 发送停止信号 */I2C_GenerateSTOP(DS3231_I2Cx, ENABLE);return 1;
}/*** @brief   从DS3231里面读取一个字节数据 * @param   *     @arg data:存放从DS3231读取的数据*      @arg ReadAddr:读取数据的DS3231的地址* @retval data:返回数据.*/
uint8_t I2C_DS3231_DataRead(u8 ReadAddr)
{uint8_t data;I2CTimeout = I2CT_LONG_TIMEOUT;/* 等待空闲 */while(I2C_GetFlagStatus(DS3231_I2Cx, I2C_FLAG_BUSY)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(9);} /* 产生 I2C 起始信号 */I2C_GenerateSTART(DS3231_I2Cx, ENABLE);/* 设置超时等待时间 */I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV5 事件并清除标志*/while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(10);}/* 发送 DS3231 设备地址,写 */I2C_Send7bitAddress(DS3231_I2Cx, DS3231_ADDRESS, I2C_Direction_Transmitter);/* 设置超时等待时间 */I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV6 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(11);}/* 通过重新设置 PE 位清除 EV6 事件  */I2C_Cmd(DS3231_I2Cx, ENABLE);/* 发送要读取的 DS3231 内部地址(即 DS3231 内部存储器的地址) */I2C_SendData(DS3231_I2Cx, ReadAddr);/* 设置超时等待时间 */  I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV8 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(12);}/* 产生第二次 I2C 起始信号 */  I2C_GenerateSTART(DS3231_I2Cx, ENABLE);/* 设置超时等待时间 */I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV5 事件并清除标志*/while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_MODE_SELECT)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(13);}/* 发送 DS3231 设备地址,读 */I2C_Send7bitAddress(DS3231_I2Cx, DS3231_ADDRESS, I2C_Direction_Receiver);/* 设置超时等待时间 */I2CTimeout = I2CT_FLAG_TIMEOUT;/* 检测 EV6 事件并清除标志 */while(!I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(14);}/* 发送非应答信号 */I2C_AcknowledgeConfig(DS3231_I2Cx, DISABLE);/* 发送停止信号 */I2C_GenerateSTOP(DS3231_I2Cx, ENABLE);/* 检测 EV7 事件并清除标志 */    I2CTimeout = I2CT_LONG_TIMEOUT;while(I2C_CheckEvent(DS3231_I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)==0)  {if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);} /* 通过 I2C,从设备中读取一个字节的数据 */data = I2C_ReceiveData(DS3231_I2Cx);     /* 使能应答,方便下一次 I2C 传输 */I2C_AcknowledgeConfig(DS3231_I2Cx, ENABLE);return data;
}/*** @brief  等待 DS3231 到准备状态* @param  无* @retval 无*/
void I2C_WaitDs3231StandbyState(void)
{vu16 SR1_Tmp = 0;do{/* 发送起始信号 */I2C_GenerateSTART(DS3231_I2Cx, ENABLE);/* 读 I2C1 SR1 寄存器 */SR1_Tmp = I2C_ReadRegister(DS3231_I2Cx, I2C_Register_SR1);/* 发送 DS3231 地址 + 方向 */I2C_Send7bitAddress(DS3231_I2Cx, DS3231_ADDRESS, I2C_Direction_Transmitter);}while(!(I2C_ReadRegister(DS3231_I2Cx, I2C_Register_SR1) & 0x0002));/* 清除 AF 位 */I2C_ClearFlag(DS3231_I2Cx, I2C_FLAG_AF);/* 发送停止信号 */    I2C_GenerateSTOP(DS3231_I2Cx, ENABLE);
}/*** @brief   BCD(8421)转DEC.* @param  val:BCD码.* @retval i:DEC码.*/
uint8_t BCD_DEC(u8 val)
{u8 i;i= val&0x0f;val >>= 4;val &= 0x0f;val *= 10;i += val;    return i;
}/*** @brief   BCD(8421)转DEC.* @param  val:DEC码.* @retval k:BCD码.*/
uint8_t DEC_BCD(u8 val)
{u8 i,j,k;i=val/10;j=val%10;k=j+(i<<4);return k;
}/*** @brief   超时报警处理.* @param  errorCode:错误代码,可以用来定位是哪个环节出错.* @retval 返回0,表示IIC读取失败.*/
static  uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{/* 使用串口 printf 输出错误信息,方便调试 */DS3231_ERROR("I2C 等待超时!errorCode = %d",errorCode);   return 0;
}/*** @brief   时间设置* @param   *       @arg   分别输入 年 月 日 星期 时 分 秒* @retval 无*/
void I2C_DS3231_SetTime(u8 yea,u8 mon,u8 da,u8 we,u8 hou,u8 min,u8 sec)
{u8 temp=0;temp=DEC_BCD(yea);I2C_DS3231_ByteWrite(0x06,temp);temp=DEC_BCD(mon);I2C_DS3231_ByteWrite(0x05,temp);temp=DEC_BCD(da);I2C_DS3231_ByteWrite(0x04,temp);//  temp=DEC_BCD(we);
//  I2C_DS3231_ByteWrite(0x03,temp);temp=DEC_BCD(hou);I2C_DS3231_ByteWrite(0x02,temp);temp=DEC_BCD(min);I2C_DS3231_ByteWrite(0x01,temp);temp=DEC_BCD(sec);I2C_DS3231_ByteWrite(0x00,temp);
}   /*** @brief    获取时间* @param   *       @arg pBuffer:存放从DS3231读取的数据的缓冲区指针*     @arg ReadAddr:读取数据的DS3231的地址*   @arg NumByteToWrite:要从DS3231读取的字节数* @retval 返回1,表示读取成功.*/
void I2C_DS3231_getTime(void)
{calendar.year=I2C_DS3231_DataRead(0x06);  calendar.year=BCD_DEC(calendar.year);calendar.month=I2C_DS3231_DataRead(0x05); calendar.month=BCD_DEC(calendar.month);calendar.date=I2C_DS3231_DataRead(0x04);  calendar.date=BCD_DEC(calendar.date);calendar.week=I2C_DS3231_DataRead(0x03);  calendar.week=BCD_DEC(calendar.week);calendar.hour=I2C_DS3231_DataRead(0x02); calendar.hour&=0x3f;                   calendar.hour=BCD_DEC(calendar.hour);calendar.min=I2C_DS3231_DataRead(0x01);calendar.min=BCD_DEC(calendar.min);calendar.sec=I2C_DS3231_DataRead(0x00);calendar.sec=BCD_DEC(calendar.sec);
}/*** @brief 保存用户使用串口设置的时间* @param   *        @arg tm:用于设置RTC时间的结构体指针* @retval */
void Time_Regulate_Get(_calendar_obj *tm)
{uint32_t temp_num = 0;uint8_t day_max=0 ;printf("\r\n=========================设置时间==================");do {printf("\r\n  请输入年份(Please Set Years),范围[2000~2255],输入字符后请加回车:");scanf("%d",&temp_num);if(temp_num <2000 || temp_num >65535){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{     printf("\n\r  年份被设置为: %d\n\r", temp_num);temp_num-=2000;DEC_BCD(temp_num);printf("\n\r  年份被设置为11: %d\n\r", temp_num);tm->year = temp_num;printf("year = %d  %d\n",calendar.year,temp_num);break;}}while(1);do {printf("\r\n  请输入月份(Please Set Months):范围[1~12],输入字符后请加回车:");scanf("%d",&temp_num);if(temp_num <1 || temp_num >12){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{     printf("\n\r  月份被设置为: %d\n\r", temp_num);DEC_BCD(temp_num);tm->month = temp_num;break;}}while(1);/*根据月份计算最大日期*/switch(tm->month){case 1:case 3:case 5:case 7:case 8:case 10:case 12:                 day_max = 31;break;case 4:case 6:case 9:case 11:day_max = 30;break;case 2:                    /*计算闰年*/if(((tm->year+2000)%4==0) &&(((tm->year+2000)%100!=0) || ((tm->year+2000)%400==0))) {day_max = 29;} else {day_max = 28;}break;           }do {               printf("\r\n  请输入日期(Please Set Months),范围[1~%d],输入字符后请加回车:",day_max);scanf("%d",&temp_num);if(temp_num <1 || temp_num >day_max){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{printf("\n\r  日期被设置为: %d\n\r", temp_num);DEC_BCD(temp_num);tm->date = temp_num;break;}}while(1);GregorianDay( tm );do {              printf("\r\n  请输入时钟(Please Set Hours),范围[0~23],输入字符后请加回车:");scanf("%d",&temp_num);if( temp_num >23){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{printf("\n\r  时钟被设置为: %d\n\r", temp_num);DEC_BCD(temp_num);tm->hour = temp_num;break;}}while(1);do {                printf("\r\n  请输入分钟(Please Set Minutes),范围[0~59],输入字符后请加回车:");scanf("%d",&temp_num);if( temp_num >59){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{printf("\n\r  分钟被设置为: %d\n\r", temp_num);DEC_BCD(temp_num);tm->min = temp_num;break;}}while(1);do {               printf("\r\n  请输入秒钟(Please Set Seconds),范围[0~59],输入字符后请加回车:");scanf("%d",&temp_num);if( temp_num >59){printf("\r\n 您输入的数字是:%d,不符合要求",temp_num);}else{printf("\n\r  秒钟被设置为: %d\n\r", temp_num);DEC_BCD(temp_num);tm->sec = temp_num;break;}}while(1);USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
}/*** @brief   获取温度* @param  无* @retval 无*/
void I2C_DS3231_getTemperature(void)
{I2C_DS3231_ByteWrite(DS3231_CONTROL, 0x20|0x05);calendar.temperature=I2C_DS3231_DataRead(DS3231_TEMPERATUREH);
}/*计算公历天数得出星期*/
void GregorianDay(_calendar_obj * tm)
{int leapsToDate;int lastYear;int day;int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };lastYear=tm->year-1;/*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/if((tm->year%4==0) &&((tm->year%100!=0) || (tm->year%400==0)) &&(tm->month>2)) {/** We are past Feb. 29 in a leap year*/day=1;} else {day=0;}day += lastYear*365 + leapsToDate + MonthOffset[tm->month-1] + tm->date; /*计算从公元元年元旦到计数日期一共有多少天*/tm->week=day%7; //算出星期
}/*********************************************END OF FILE**********************/

3、主函数调用

/********************************************************************************* @file    main.c * @author  兲涳* @version V1.0* @date    2020-11-16* @brief   ******************************************************************************* @attention* I2C_2 RTC(DS3231)测试,测试信息通过USART1打印在电脑调试助手上,通过串口设置时间* !!!串口输入  t  回车 ,进行设置时间。*******************************************************************************/  /* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "bsp_usart.h"
#include "bsp_i2c_ds3231.h"
#include <string.h>/* Private typedef -----------------------------------------------------------*/
uint8_t i=0;
extern _calendar_obj calendar;  //日历结构体/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define SOFT_DELAY      Delay(0x4FFFFF);/* Private variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void Delay(__IO u32 nCount); /*** @brief  主函数* @param  无  * @retval 无*/
int main(void)
{ /* 初始化USART 配置模式为 115200 8-N-1 */USART_Config();printf("\nDS3231   RTC时钟\n");/* I2C 外设初(DS3231)始化 */I2C_DS3231_Init();
//  I2C_DS3231_SetTime(20,8,24,1,13,43,20);while(1){SOFT_DELAY;if(i==1){Time_Regulate_Get( &calendar );I2C_DS3231_SetTime(calendar.year, calendar.month, calendar.date, calendar.week, calendar.hour, calendar.min, calendar.sec);i=0;}I2C_DS3231_getTime();     //获取时间I2C_DS3231_getTemperature();      //获取温度printf("%d年%d月%d日%d时%d分%d秒 星期%d 温度%d\n",calendar.year+2000,calendar.month,calendar.date,\calendar.hour,calendar.min,calendar.sec,calendar.week,calendar.temperature);//打印到串口屏不能有printf("\n");换行!!!  }
}   /*** @brief  延时函数* @param  无  * @retval 无*/
void Delay(__IO uint32_t nCount)     //简单的延时函数
{for(; nCount != 0; nCount--);
}
/*********************************************END OF FILE**********************/

4、使用

在串口工具上,输入t,即可进入设置时钟。该程序自动在串口上打印时间及温度

基于DS3231时钟模块的stm32 程序,源码相关推荐

  1. 基于DS3231时钟模块的stm32 Hal库程序,源码

    关于DS3231模块介绍我在我的博客基于DS3231时钟模块的stm32 程序,源码中有介绍 ,大家可以自己看下.我这篇直接讲HAL的代码. 一.配置IO /**/****************** ...

  2. [附源码]计算机毕业设计Python+uniapp基于Android 工厂考勤系统4h291(程序+源码+LW+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于Android 工厂考勤系统4h291(程序+源码+LW+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环境 ...

  3. [附源码]计算机毕业设计Python+uniapp基于Android的自来水收费系统3e359(程序+源码+LW+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于Android的自来水收费系统3e359(程序+源码+LW+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环 ...

  4. [附源码]计算机毕业设计Python+uniapp基于Android的校园考勤APPo0400(程序+源码+LW+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于Android的校园考勤APPo0400(程序+源码+LW+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环 ...

  5. 一个基于codeigniter的淘宝客程序源码,适合学习参考,京东拼多多淘宝联盟api

    一个基于codeigniter的淘宝客程序源码,直接调用淘宝联盟api,效果图如下: 该源码需要的环境是php5.6,适合初学者开发学习之用. 下载资源地址分享, https://download.c ...

  6. [附源码]计算机毕业设计Python+uniapp基于MVVM在线电影购票APP05s75(程序+源码+LW+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于MVVM在线电影购票APP05s75(程序+源码+LW+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环境配 ...

  7. [附源码]计算机毕业设计Python+uniapp基于Android的减肥菜谱APPn0n19(程序+源码+LW+远程部署)

    [附源码]计算机毕业设计Python+uniapp基于Android的减肥菜谱APPn0n19(程序+源码+LW+远程部署) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行环 ...

  8. php 授权模块,PHP免授权功能模块:智慧农场小程序 1.8.9后台模块前端小程序源码模块插件...

    功能模块:智慧农场小程序 1.8.9后台模块+前端小程序源码 内容介绍: 版本号:1.8.9 – 普通版注意:1.本次更新需要重新上传小程序 2.本次更新内容较多,请注意备份–新增小程序自己添加收货地 ...

  9. 基于TCP网络通信的自动升级程序源码分析-客户端接收文件

    升级程序客户端接收文件 /// <summary>/// 文件数据缓存 索引是 ConnectionInfo对象 数据包的顺序号 值是数据/// </summary>Dicti ...

最新文章

  1. numpy 数组 维度 大小 形状
  2. echarts 浏览器兼容性_谷歌浏览器不再使用quot;黑名单quot; / iPhone可能放弃lightning充电口//微软中国被列为被执行人/QQ 音乐上线...
  3. 面向项目(十)—— 头文件、源文件的组织
  4. 30.TCP/IP 详解卷1 --- 其他的 TCP/IP 应用程序
  5. 拓端tecdat|使用R语言做极大似然估计实例
  6. 深入 Composer autoload
  7. 基于cocos creator 3.4 实现虚拟摇杆
  8. 【转】GB2312 编码
  9. Windows安装补丁_勒索病毒_补丁号
  10. php程序员 合川_重庆PHP程序员工资如何?
  11. py-01-LINUX
  12. 如何设置交易滑点?精确到tick 测算期货冲击成本(附源码)
  13. JS跨域设置和取Cookie(二)
  14. pdf怎么编辑连续页码
  15. 说说亲身经历的草根seo的辛酸
  16. android 实现屏幕录制功能,Android实现屏幕录制功能
  17. [文摘201009]演讲录全文:美国世界帝国战略与中国的危机 - 戴旭
  18. 使用WinDbg调试SQL Server——入门
  19. YUV422 YUV420 Planar Semi-Planar详解
  20. 软件测试交付物、交付文档、测试产物等如何写?有何依据?模板是是什么?

热门文章

  1. 计算器算贝塞尔公式_二手车评估计算器是如何估价的?
  2. 【预测模型】基于人工鱼群算法优化BP神经网络实现数据预测matlab源码
  3. 【文学文娱】你会《做饭》吗?
  4. Win7的定时关机功能(计划任务+shutdown.exe实现)
  5. linux c语言结构体初始化,Linux c中 结构体初始化方式
  6. 如何用计算机算出女生生日,怎么用 iPhone 的计算器拿到妹子的手机号码?
  7. Azkaban 环境搭建及executor became inactive问题
  8. 我宁愿臭不要脸,也不要所谓的假装矜持!
  9. java 浏览器 安全_使用 IE 浏览器浏览网页时,出于安全方面的考虑,需要禁止执行 Java Script ,可以在 IE 中 ( )。...
  10. 怎么样快速学习AngularJS? - 左正 - 博客园