刚刚写完DS3231时钟芯片的驱动程序。这里开源出来供大家使用。需要的自取。
先简单介绍下这个芯片,然后直接给驱动代码以及示例代码。

DS3231简介

简介

DS3231是一款低成本、高精度I2C实时时钟(RTC),具有集成的温补晶体振荡器(TCXO)和晶体。该器件包含电池输入端,断开主电源时认可保持精确的计时。其提供年、月、日、星期、时、分、秒信息,提供有效期到2100年的闰年补偿。

其带有两个提供不同精度的日历闹钟,可在指定时刻在引脚上产生中断信号。

支持快速(400kHz)I2C接口通讯。

时钟精度在0℃到+40℃为±2ppm,即一个月可能偏离5s多;在-40℃到+85℃为±3.5ppm。

除了时钟外,还提供精度为±3℃的数字温度传感器输出,内部会使用这个温度传感器自动进行补偿以保证时间精度。

典型工作电路

框图

寄存器

DS3231提供如下寄存器:

与DS3231的控制和交互就是通过存取这几个寄存器来实现的,驱动代码中提供了所有寄存器的结构体以及对寄存器的存取函数。

具体寄存器的意义请自己参照数据手册。

与芯片的I2C通讯

I2C通讯的基本原理可以见我的上一个文章https://blog.csdn.net/lin_strong/article/details/80259571,翻译的MC9S12XEP100的数据手册,里头有对I2C通讯的详细描述。



DS3231的主叫地址固定为0b1101000,其内部存在一个寄存器指针,指向下一次读/写的寄存器,每次读/写一次后指针都会自增1,到最后一个寄存器后再指向第一个寄存器。
进行写操作时第一个数据字节会对指针值进行修改。

驱动中提供的函数即封装了这个过程。

代码及测试

驱动代码

DS3231Driver.h

/*
*******************************************************************************************
*
*
*                                   DS3231 DRIVER MODULE
*                                      DS3231驱动模块
*
* File : DS3231Driver.h
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2018/05/14
* version: V1.0
* History: 2018/05/14  V1.0   the prototype
*********************************************************************************************
*/#ifndef   DS3231_DRIVER_H
#define   DS3231_DRIVER_H/*
********************************************************************************************
*                                   MISCELLANEOUS
********************************************************************************************
*/#ifndef  FALSE
#define  FALSE    0
#endif#ifndef  TRUE
#define  TRUE     1
#endif/*
******************************************************************************************
*                                    CONSTANT
******************************************************************************************
*/
// address of register
typedef enum{RegAddr_Sec,    // Seconds              00-59RegAddr_Min,    // Minutes              00-59RegAddr_Hour,   // Hours                1–12 + AM/PM 00–23RegAddr_Day,    // Day                  1 - 7RegAddr_Date,   // Data                 01-31RegAddr_CMon,   // Century and month    Century + 01–12RegAddr_Year,   // Year                 00 - 99RegAddr_Sec_A1, // Alarm 1 Seconds      00-59RegAddr_Min_A1, // Alarm 1 Minutes      00-59RegAddr_Hour_A1,// Alarm 1 Hours        1–12 + AM/PM 00–23RegAddr_Da_A1,  // Alarm 1 Day/Date     1 - 7 / 1 – 31RegAddr_Min_A2, // Alarm 2 Minutes      00-59RegAddr_Hour_A2,// Alarm 2 Hours        1–12 + AM/PM 00–23RegAddr_Da_A2,  // Alarm 2 Day/Date     1 - 7 / 1 – 31RegAddr_Control,// ControlRegAddr_CtlStat,// Control/StatusRegAddr_AgOfset,// Aging offsetRegAddr_TempMSB,// MSB of TempRegAddr_TempLSB,// LSB of Temp
}DS3231REG_ADDR;
#define DS3231REG_ADDR_MAX  RegAddr_TempLSB
/*
*******************************************************************************************
*                               CONFIGURE 主配置
*******************************************************************************************
*/
#define DS3231_CALLADDR     0b1101000       // DS32331的主叫地址/*
****************************************************************************************
*                                  ERROR CODES
****************************************************************************************
*/#define DS3231_ERR_NULL   0      // if success
#define DS3231_ERR_COMM   1      // any error in communication
#define DS3231_ERR_REG    2      // wrong register
#define DS3231_ERR_ARG    3      // if wrong argument/*
******************************************************************************************
*                                  TYPE DEFINE
******************************************************************************************
*/// struct of DS3231 register
typedef struct {unsigned int sec_sd: 4; // ones digit of second  秒的个位unsigned int sec_td: 3; // tens digit of second  秒的十位unsigned int       : 1;
} REG_SEC;typedef struct {unsigned int min_sd: 4; // ones digit of minute 分的个位unsigned int min_td: 3; // tens digit of minute   分的十位unsigned int       : 1;
} REG_MIN;typedef union {struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:1; // tens digit of hour 分的个位unsigned int isPM   :1; // whether is pmunsigned int is12sys:1; // whether is 12 hours system. unsigned int        :1;}SYS12;struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:2; // tens digit of hour   分的个位unsigned int is12sys:1; // whether is 12 hours system. unsigned int        :1;}SYS24;
} REG_HOUR;typedef struct {unsigned int day    : 3; // the day of the week unsigned int        : 5;
} REG_DAY;typedef struct {unsigned int date_sd: 4; // ones digit of second  秒的个位unsigned int date_td: 2; // tens digit of second  秒的十位unsigned int        : 2;
} REG_DATE;typedef struct {unsigned int mon_sd: 4; // ones digit of month 月的个位unsigned int mon_td: 1; // tens digit of month 月的个位unsigned int       : 2; unsigned int century:1; // hundreds digit of year
} REG_CMON;typedef struct {unsigned int year_sd: 4; // ones digit of year 月的个位unsigned int year_td: 4; // tens digit of year 月的个位
} REG_YEAR;typedef struct {unsigned int sec_sd: 4; // ones digit of second  秒的个位unsigned int sec_td: 3; // tens digit of second  秒的十位unsigned int A1M1  : 1;
} REG_SEC_A1;typedef struct {unsigned int min_sd: 4; // ones digit of minute 分的个位unsigned int min_td: 3; // tens digit of minute   分的十位unsigned int A1M2  : 1;
} REG_MIN_A1;typedef union {struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:1; // tens digit of hour 分的个位unsigned int isPM   :1; // whether is pmunsigned int is12sys:1; // whether is 12 hours system. unsigned int A1M3   :1;}SYS12;struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:2; // tens digit of hour 分的个位unsigned int is12sys:1; // whether is 12 hours system. unsigned int A1M3   :1;}SYS24;
} REG_HOUR_A1;typedef union {struct{unsigned int day    : 4; // the day of the week unsigned int        : 2;unsigned int isDY   : 1; // day selectedunsigned int A1M4   : 1;}DAY;struct{unsigned int date_sd: 4; // ones digit of dateunsigned int date_td: 2; // tens digit of dateunsigned int isDY   : 1; // day selectedunsigned int A1M4   : 1;}DATE;
} REG_DA_A1;typedef struct {unsigned int min_sd: 4; // ones digit of minute 分的个位unsigned int min_td: 3; // tens digit of minute   分的十位unsigned int A2M2  : 1;
} REG_MIN_A2;typedef union {struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:1; // tens digit of hour 分的个位unsigned int isPM   :1; // whether is pmunsigned int is12sys:1; // whether is 12 hours system. unsigned int A2M3   :1;}SYS12;struct{unsigned int hour_sd:4; // ones digit of hour 分的个位unsigned int hour_td:2; // tens digit of hour 分的个位unsigned int is12sys:1; // whether is 12 hours system. unsigned int A2M3   :1;}SYS24;
} REG_HOUR_A2;typedef union {struct{unsigned int day    : 4; // the day of the week unsigned int        : 2;unsigned int isDY   : 1; // day selectedunsigned int A2M4   : 1;}DAY;struct{unsigned int date_sd: 4; // ones digit of dateunsigned int date_td: 2; // tens digit of dateunsigned int isDY   : 1; // day selectedunsigned int A2M4   : 1;}DATE;
} REG_DA_A2;typedef struct{unsigned int A1IE  : 1;unsigned int A2IE  : 1;unsigned int INTCN : 1;unsigned int RS1   : 1;unsigned int RS2   : 1;unsigned int CONV  : 1;unsigned int BBSQW : 1;unsigned int EOSC  : 1;
} REG_CONTROL;typedef struct{unsigned int A1IF   : 1;unsigned int A2IF   : 1;unsigned int BSY    : 1;unsigned int EN32kHz: 1;unsigned int        : 3;unsigned int OSF    : 1;
} REG_CTLSTAT;typedef struct{unsigned int DATA : 7;unsigned int SIGN : 1;
} REG_AGOFSET;typedef struct{char DATA;
} REG_TEMPMSB;typedef struct{unsigned int      : 6;unsigned int DATA : 2;
} REG_TEMPLSB;// type of module
typedef struct {REG_SEC  sec;REG_MIN  min;REG_HOUR hour;REG_DAY  day;REG_DATE date;REG_CMON cmon;REG_YEAR year;
} TIME_STRUCT,*pTIME_STRUCT;typedef struct{REG_TEMPMSB integral;      // integral partREG_TEMPLSB fractional;    // fractional part
} TEMP_STRUCT,*pTEMP_STRUCT;typedef struct{unsigned int errcode : 4; // see DS3231_ERR_XXXunsigned int commerr : 4; // hold the errcode by user defined iic functions.
} DS3231_ERRCODE;/*
************************************************************************************
*                          FUNCTION PROTOTYPES  函数原型
************************************************************************************
*/unsigned char DS3231_Init(void);
DS3231_ERRCODE DS3231_GetReg(DS3231REG_ADDR reg,unsigned char *rst);
DS3231_ERRCODE DS3231_SetReg(DS3231REG_ADDR reg,unsigned char value);
DS3231_ERRCODE DS3231_GetRegs(DS3231REG_ADDR reg,unsigned char *pBuf,unsigned short len);
DS3231_ERRCODE DS3231_SetRegs(DS3231REG_ADDR reg,unsigned char *pBuf,unsigned short len);DS3231_ERRCODE DS3231_SetTime(pTIME_STRUCT val);
DS3231_ERRCODE DS3231_GetTime(pTIME_STRUCT rst);
DS3231_ERRCODE DS3231_GetTemp(pTEMP_STRUCT rst);// 用户需要实现这几个函数以使模块能与DS3231进行IIC通讯
// Arguments: calAddr      7bits calling address
//            pBuf         pointer to the send/recv buffer
//            len          length of datas to be send/recv
//            rst          pointer to the return value
//            val          the byte to send
// return   : 0            if success
//            1 - 15       errcode of IIC communication.
//                         meaning of errcode of these functions should be exactly same.
extern unsigned char IIC_ReadBurst(unsigned char calAddr,unsigned char *pBuf,unsigned short len);
extern unsigned char IIC_SendBurst(unsigned char calAddr,unsigned char *pBuf,unsigned short len);
extern unsigned char IIC_ReadByte(unsigned char calAddr,unsigned char *rst);
extern unsigned char IIC_SendByte(unsigned char calAddr,unsigned char val);/*
************************************************************************************
*                          ERROR CHECK 错误检查
************************************************************************************
*/#endif  // of DS3231_DRIVER_H

DS3231Driver.c

/*
*******************************************************************************************
*
*
*                                   DS3231 DRIVER MODULE
*                                      DS3231驱动模块
*
* File : DS3231Driver.c
* By   : Lin Shijun(http://blog.csdn.net/lin_strong)
* Date:  2018/05/14
* version: V1.0
* History: 2018/05/14  V1.0   the prototype
*********************************************************************************************
*//*
*********************************************************************************************
*                                       INCLUDES
*********************************************************************************************
*/
#include <string.h>
#include "DS3231Driver.h"/*
*********************************************************************************************
*                                       LOCAL FUNCTION
*********************************************************************************************
*/#define regCheck()     if(reg > DS3231REG_ADDR_MAX){err.errcode = DS3231_ERR_REG;  return err;}
#define lenCheck()     if(len > (DS3231REG_ADDR_MAX + 1) || len == 0){err.errcode = DS3231_ERR_ARG;  return err;}
/*
*********************************************************************************************
*                                       LOCAL VARIABLE
*********************************************************************************************
*/
// 发送缓存
static unsigned char Sendbuf[DS3231REG_ADDR_MAX + 2];/*
*********************************************************************************************
*                                        DS3231_Init()
*
* Description : Initialize DS3231 support hardware(marco style).  初始化DS3231硬件
*
* Arguments   :
*
* Return      : DS3231_ERR_NULL       if success.
*
* Note(s)     :
*********************************************************************************************
*/unsigned char DS3231_Init(void){return DS3231_ERR_NULL;
}/*
*********************************************************************************************************
*                                        DS3231_getReg()
*
* Description : get a register value of DS3231.
*
* Arguments   : reg       the register to get value.
*               rst       return value of result.
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*                 DS3231_ERR_REG     if unknown register.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
*
* Note:
*********************************************************************************************************
*/DS3231_ERRCODE DS3231_GetReg(DS3231REG_ADDR reg,unsigned char *rst){DS3231_ERRCODE err = {0};unsigned char commerr;regCheck();if((commerr = IIC_SendByte(DS3231_CALLADDR,(unsigned char)reg)) == 0 &&  // 写入寄存器指针(commerr = IIC_ReadByte(DS3231_CALLADDR,rst)) == 0){                  // 然后读取一个字节err.errcode = DS3231_ERR_NULL;}else{err.errcode = DS3231_ERR_COMM;}err.commerr = commerr;return err;
}
/*
*********************************************************************************************************
*                                        DS3231_SetReg()
*
* Description : set a register of DS3231.
*
* Arguments   : reg       the register to get value.
*               rst       return value of result.
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*                 DS3231_ERR_REG     if unknown register.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
* Note:
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_SetReg(DS3231REG_ADDR reg,unsigned char value){DS3231_ERRCODE err = {0};unsigned char commerr;regCheck();Sendbuf[0] = (unsigned char)reg;Sendbuf[1] = value;if((commerr = IIC_SendBurst(DS3231_CALLADDR,Sendbuf,2)) == 0)err.errcode =  DS3231_ERR_NULL;elseerr.errcode =  DS3231_ERR_COMM;err.commerr = commerr;return err;
}
/*
*********************************************************************************************************
*                                        DS3231_GetRegs()
*
* Description : get sereval registers' value of DS3231.
*
* Arguments   : reg      the first register to get value.
*               pBuf      return value of register.
*               len       how many registers to get value (1 - (DS3231REG_ADDR_MAX + 1))
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*                 DS3231_ERR_REG     if unknown register.
*                 DS3231_ERR_ARG     if len out of range.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
* Note:
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_GetRegs(DS3231REG_ADDR reg,unsigned char *pBuf,unsigned short len){DS3231_ERRCODE err = {0};unsigned char commerr;regCheck();lenCheck();if((commerr = IIC_SendByte(DS3231_CALLADDR,(unsigned char)reg)) == 0 &&  // 写入寄存器指针(commerr = IIC_ReadBurst(DS3231_CALLADDR,pBuf,len)) == 0){            // 然后读取一个字节err.errcode = DS3231_ERR_NULL;}else{err.errcode = DS3231_ERR_COMM;}err.commerr = commerr;return err;
}
/*
*********************************************************************************************************
*                                        DS3231_SetRegs()
*
* Description : set sereval registers' value of DS3231.
*
* Arguments   : reg       the first register to set value.
*               pBuf      point to the value of registers to set.
*               len       how many registers to set value (1 - (DS3231REG_ADDR_MAX + 1))
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*                 DS3231_ERR_REG     if unknown register
*                 DS3231_ERR_ARG     if len out of range.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
*
* Note:
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_SetRegs(DS3231REG_ADDR reg,unsigned char *pBuf,unsigned short len){DS3231_ERRCODE err = {0};unsigned char commerr;regCheck();lenCheck();Sendbuf[0] = (unsigned char)reg;memcpy(Sendbuf+1,pBuf,len);if((commerr = IIC_SendBurst(DS3231_CALLADDR,Sendbuf,len + 1)) == 0){  // 写入寄存器指针err.errcode = DS3231_ERR_NULL;}else{err.errcode = DS3231_ERR_COMM;}err.commerr = commerr;return err;
}
/*
*********************************************************************************************************
*                                        DS3231_SetTime()
*
* Description : set time of DS3231.
*
* Arguments   : val       the time to set
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
* Note:
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_SetTime(pTIME_STRUCT val){return DS3231_SetRegs(RegAddr_Sec,(unsigned char *)val,sizeof(TIME_STRUCT));
}
/*
*********************************************************************************************************
*                                        DS3231_GetTime()
*
* Description : get time of DS3231.
*
* Arguments   : rst       the time result.
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
* Note:
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_GetTime(pTIME_STRUCT rst){return DS3231_GetRegs(RegAddr_Sec,(unsigned char *)rst,sizeof(TIME_STRUCT));
}
/*
*********************************************************************************************************
*                                        DS3231_GetTemp()
*
* Description : get temperature measured by DS3231.
*
* Arguments   : rst       return the temperature measured.
*                         = (rst->integral.DATA).(rst->fractional.DATA * 0.25)
*                         for example:
*                           if rst->integral.DATA = -4, rst->fractional.DATA = 3
*                           then  temperature = -4.75 C
*                           if rst->integral.DATA = 25, rst->fractional.DATA = 1
*                           then  temperature = +25.25 C
*
* Return      : .errcode:
*                 DS3231_ERR_NULL    if success.
*                 DS3231_ERR_COMM    if error.
*               .commerr:
*                 errcode returned by user defined IIC functions if DS3231_ERR_COMM.
* Note        : 1. DS3231 will measure temperature every 64 seconds once powered
*                  by Vcc or once communicated when powerd by battery.
*               2. you can also start the convertion by set CONV in Control
*                  register.
*********************************************************************************************************
*/
DS3231_ERRCODE DS3231_GetTemp(pTEMP_STRUCT rst){return DS3231_GetRegs(RegAddr_TempMSB,(unsigned char *)rst,sizeof(TEMP_STRUCT));
}

DS3231_G/SetReg(s)对DS3231寄存器读写操作进行封装。
模块要求用户按照要求提供错误码风格的IIC通讯函数,并在发生通讯错误时把用户函数的错误码一同返回。

由于时间和温度的使用较频繁,提供了专门的读写函数。

时间转换助手

DS3231TimeHelper.h

/*
*******************************************************************************************
*
*                                   DS3231 TIME HELPER MODULE
*
* File : DS3231TimeHelper.h
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date:  2019/09/26
* version: V1.0
* History:
* note   : the convert interfaces for DS3231 time.
*********************************************************************************************
*/
#ifndef _DS3231TimeHelper_H
#define _DS3231TimeHelper_H#include "DS3231Driver.h"
#include "TimeExt.h"
#include "common.h"// only support year from 2000 to 2199
#define DS3231_BASEYEAR   2000void DS3231TimeToSystemTime(struct tm *dst, const TIME_STRUCT *src);
void SystemTimeToDS3231Time(TIME_STRUCT *dst, const struct tm *src);
BOOL DS3231TimeValid(const TIME_STRUCT *time);#endif

其中TimeExt.h是引用的我自己写的time标准库实现:
https://blog.csdn.net/lin_strong/article/details/102619616

只是为了节省空间直接用了里头的

const int16_t TimeExt_lpdays[] = {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
const int16_t TimeExt_days[] = {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};

如果不需要使用这个实现的话,就把

#include "TimeExt.h"

改为

#include <time.h>

然后在模块内部加入上面那两个常量数组就好了。

DS3231TimeHelper.c

/*
*******************************************************************************************
*
*                                   DS3231 TIME HELPER MODULE
*
* File : DS3231TimeHelper.c
* By   : Lin Shijun(https://blog.csdn.net/lin_strong)
* Date:  2019/09/26
* version: V1.0
* History:
* note   : the convert interfaces for DS3231 time.
*********************************************************************************************
*/
#include "DS3231TimeHelper.h"
#include <stdint.h>#pragma MESSAGE DISABLE C2705
#pragma MESSAGE DISABLE C12056
void DS3231TimeToSystemTime(struct tm *dst, const TIME_STRUCT *src){uint16_t tmp;const int16_t * mdays;if(dst == NULL || src == NULL)return;dst->tm_sec = src->sec.sec_sd + src->sec.sec_td * 10;dst->tm_min = src->min.min_sd + src->min.min_td * 10;if(src->hour.SYS12.is12sys){tmp = src->hour.SYS12.hour_sd + src->hour.SYS12.hour_td * 10;tmp = (tmp == 12)? 0: tmp;    // 12:30 am = 00:30(24h);    12:30pm = 12:30(24h)dst->tm_hour = (src->hour.SYS12.isPM)? tmp + 12: tmp;}else{dst->tm_hour = src->hour.SYS24.hour_sd + src->hour.SYS24.hour_td * 10;}dst->tm_mday = src->date.date_sd +  src->date.date_td * 10;dst->tm_mon = src->cmon.mon_sd + src->cmon.mon_td * 10 - 1;dst->tm_year = src->year.year_sd + src->year.year_td * 10 + (DS3231_BASEYEAR - 1900) + src->cmon.century * 100;dst->tm_wday = src->day.day - 1;          // treat TIME_STRUCT.day 1 as Sundayif(dst->tm_mon < 12){tmp = dst->tm_year + 1900;mdays = (IS_LEAP_YEAR(tmp))?TimeExt_lpdays: TimeExt_days;dst->tm_yday = mdays[dst->tm_mon] + dst->tm_mday;}dst->tm_isdst = 0;dst->tm_gmtoff = -1;
}void SystemTimeToDS3231Time(TIME_STRUCT *dst, const struct tm *src){uint16_t tmp;if(dst == NULL || src == NULL)return;if(src->tm_year < (DS3231_BASEYEAR - 1900))return;dst->sec.sec_sd = src->tm_sec % 10;dst->sec.sec_td = src->tm_sec / 10;dst->min.min_sd = src->tm_min % 10;dst->min.min_td = src->tm_min / 10;dst->hour.SYS12.is12sys = 0;  // use 24 hours systemdst->hour.SYS24.hour_sd = src->tm_hour % 10;dst->hour.SYS24.hour_td = src->tm_hour / 10;dst->date.date_sd = src->tm_mday % 10;dst->date.date_td = src->tm_mday / 10;dst->day.day = src->tm_wday + 1;tmp = src->tm_mon + 1;dst->cmon.mon_sd = tmp % 10;dst->cmon.mon_td = tmp / 10;tmp = src->tm_year - (DS3231_BASEYEAR - 1900);dst->cmon.century = tmp / 100 & 1;dst->year.year_sd = tmp % 10;tmp /= 10;dst->year.year_td = tmp % 10;
}BOOL DS3231TimeValid(const TIME_STRUCT *time){uint16_t tmp;if(time == NULL)return FALSE;// BCD check(with some range check)if(time->sec.sec_sd > 9 || time->sec.sec_td > 5 ||time->min.min_sd > 9 || time->min.min_td > 5 ||time->hour.SYS24.hour_sd > 9 ||time->day.day == 0 ||time->date.date_sd > 9 ||time->cmon.mon_sd > 9 ||time->year.year_sd > 9 || time->year.year_td > 9)return FALSE;// range checkif(time->hour.SYS12.is12sys){tmp = time->hour.SYS12.hour_sd + time->hour.SYS12.hour_td * 10;if(tmp < 1 || tmp > 12)return FALSE;}else{tmp = time->hour.SYS24.hour_sd + time->hour.SYS24.hour_td * 10;if(tmp > 23)return FALSE;}tmp = time->cmon.mon_sd + time->cmon.mon_td * 10;if(tmp == 0 || tmp > 12)return FALSE;tmp = time->date.date_sd + time->date.date_td * 10;if(tmp == 0 || tmp > 31)  // 其实更严格的检查的话得判断当前月份return FALSE;return TRUE;
}

下面给出驱动代码的使用示例:

示例代码

#include <hidef.h>      /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */
#include "DS3231Driver.h"
#include "IIC.h"
#include <stdio.h>typedef void (*near tIsrFunc)(void);
const tIsrFunc _vect @0xFFC0 = IIC_ISR;#define BUS_CLOCK 32000000
void Delay(void) {unsigned int i,j;for(i = 0; i < 100; i++)for(j = 0; j < 50000; j++);
}
void INIT_PLL(void)
{CLKSEL &= 0x7f;       //set OSCCLK as sysclkPLLCTL &= 0x8F;       //DisaKble PLL circuitCRGINT &= 0xDF;#if(BUS_CLOCK == 40000000) SYNR = 0x44;#elif(BUS_CLOCK == 32000000)SYNR = 0x43;     #elif(BUS_CLOCK == 24000000)SYNR = 0x42;#endif REFDV = 0x81;         //PLLCLK=2×OSCCLK×(SYNR+1)/(REFDV+1)=64MHz ,fbus=32MPLLCTL =PLLCTL|0x70;  //Enable PLL circuitasm NOP;asm NOP;while(!(CRGFLG&0x08)); //PLLCLK is Locked alreadyCLKSEL |= 0x80;        //set PLLCLK as sysclk
}
char strbuf[100];
volatile TIME_STRUCT time;
volatile TEMP_STRUCT temp;
unsigned char* flag = (unsigned char*)0x3F80;
void main(void) {// 18年5月11日星期五23点59分50秒time.year.year_td = 1; time.year.year_sd = 8;time.cmon.mon_td = 0;  time.cmon.mon_sd = 5;time.date.date_td = 1; time.date.date_sd = 1;time.day.day = 5;      time.hour.SYS24.is12sys = 0;time.hour.SYS24.hour_td = 2; time.hour.SYS24.hour_sd = 3;time.min.min_td = 5;   time.min.min_sd = 9;time.sec.sec_td = 5;   time.sec.sec_sd = 0;INIT_PLL();IIC_Init();DS3231_Init();EnableInterrupts;// 每次首次上电时设置当前时间if(*flag != 0xac){if(DS3231_SetTime(&time).errcode != DS3231_ERR_NULL)while(1);*flag = 0xac;        // RAM中的数据在保持上电状态时即使系统重置也不会重置,但在上电重置时会重置}for(;;) {// 读取当前时间和温度,出任意错则无限循环停止运行if(DS3231_GetTime(&time).errcode != DS3231_ERR_NULL)while(1);if(DS3231_GetTemp(&temp).errcode != DS3231_ERR_NULL)while(1);sprintf(strbuf,"year:%d%d month:%d%d date:%d%d day:%d,%d%d:%d%d:%d%d\r\nTemp:%d.%02d\r\n",time.year.year_td,time.year.year_sd,time.cmon.mon_td,time.cmon.mon_sd,time.date.date_td,time.date.date_sd,time.day.day,time.hour.SYS24.hour_td,time.hour.SYS24.hour_sd,time.min.min_td,time.min.min_sd,time.sec.sec_td,time.sec.sec_sd,temp.integral.DATA,temp.fractional.DATA * 25);Delay();}
}// 实现驱动要求的函数
unsigned char IIC_ReadBurst(unsigned char calAddr,unsigned char *pBuf,unsigned short len){return IIC_Recv(calAddr,pBuf,len);
}
unsigned char IIC_SendBurst(unsigned char calAddr,unsigned char *pBuf,unsigned short len){return IIC_Send(calAddr,pBuf,len);
}
unsigned char IIC_ReadByte(unsigned char calAddr,unsigned char *rst){return IIC_RecvChar(calAddr,rst);
}
unsigned char IIC_SendByte(unsigned char calAddr,unsigned char val){return IIC_SendChar(calAddr,&val);
}

测试结果

后记

这次对DS3231进行了简单的封装,难免会有不足或者错误之处,敬请指出。

测试中使用的IIC函数是自己封装的MC9S12XEP100的IIC模块,正在完善中,应该马上就会放出。

要求用户提供IIC函数是为了实现与硬件解耦,这样不管实际平台是怎么样的,用户只要按照要求实现IIC通讯函数就可以使用这个驱动了。

简介中完全参考Maxim的数据手册。

注意

结构体位字段的写法有移植性问题,和编译器怎么排布位域有关。要检查有没问题的话,比如设

time.year.year_td = 1; time.year.year_sd = 8;

然后调试器看下内存,对应字节应该为0x18。如果是0x81的话,需要把结构体定义中的所有位字段的位置都掉个个。

另外,还可能遇到结构体对齐特性上的移植性问题。TIME_STRUCT中的每个寄存器结构体都应该占1个byte,也就是说sizeof(TIME_STRUCT)应该等于7,sizeof(REG_SEC)应该等于1。
目前已知stm32的编译器对位域上会根据类型声明来对齐,因此对于stm32的话应该把所有的位域的类型改成unsigned char,如REG_SEC应该改成这样:

typedef struct {unsigned char sec_sd: 4; // ones digit of second  秒的个位unsigned char sec_td: 3; // tens digit of second  秒的十位unsigned char       : 1;
} REG_SEC;

这是stm32编译器自己的扩展,非语言本身规范。

更新历史

2018/05/14
2019/10/18 增加时间转换助手模块

[嵌入式开发模块]DS3231时钟芯片 驱动程序相关推荐

  1. 咚咚咚————【封装驱动】DS3231时钟芯片读写程序,分享交流自己编写的程序。

    咚咚咚----[封装驱动]DS3231时钟芯片读写程序,分享交流自己编写的程序. /******************************************** 主控芯片:STM32 Co ...

  2. DS3231时钟芯片IIC地址

    DS3231时钟芯片 寄存器地址 DS3231地址 0xd0 写 0xd1 读

  3. c语言数组实现环形缓冲区,[嵌入式开发模块]环形缓冲区/循环队列 C语言实现

    忙着毕设,很久没有写文章了,终于答辩完了,得了个校优秀毕业设计.毕设做的是个智能接口模块,用一周时间入门了,MC9S12XEP100的开发,又用一周时间入门了uC/OS-II嵌入式操作系统,在做毕设的 ...

  4. proteus设计教程-DS1302时钟芯片驱动程序

    时钟芯片DS1302电路图如下,晶振X1的频率为32.768khz 读写时间只需要调用void read_time(),void write_time()两个函数进行操作. 直接读取出来的数据是BCD ...

  5. [嵌入式开发模块]MC9S12XEP100 IIC模块 驱动程序

    此为本人写的MC9S12XEP100的IIC集成电路总线的硬件驱动程序. 文章目录 前言 相关理论 驱动模块简介 代码 驱动模块 基于UCOS-II的驱动 示例代码 代码下载 前言 相关理论 相关理论 ...

  6. [嵌入式开发模块]JY61姿态角度传感器 驱动模块

    文章目录 前言 JY61简介 概述 通信协议 驱动文件 JY61Driver.h JY61Recver.c JY61Cmder.c 依赖 使用示例 更新历史 前言 干活中用到了JY61姿态角度传感器, ...

  7. [嵌入式开发模块]AD转换芯片ADS8344驱动模块

    文章目录 芯片简介 代码 头文件 源文件 使用及示例代码 芯片简介 ADS8344是一个8通道16位模数转换器,使用SPI接口. 其可以使用单端或差分输入,单端模式时,每个CHX独立作为采样输入,测其 ...

  8. 嵌入式开发模块]AD转换芯片ADS8344驱动模块16位分辨率,程序实例

    文章目录 芯片简介 代码 头文件 源文件 使用及示例代码 芯片简介 ADS8344是一个8通道16位模数转换器,使用SPI接口. 其可以使用单端或差分输入,单端模式时,每个CHX独立作为采样输入,测其 ...

  9. [嵌入式开发模块]SHT30/20 温湿度传感器 驱动模块

    文章目录 前言 SHT30简介 概述 通信协议 驱动文件 SHT30Driver.h SHT30Recver.c SHT30Cmder.c 依赖 使用示例 更新历史 前言 干活中用到了SHT30,其实 ...

最新文章

  1. Maven构建Struts2项目
  2. 不职业不同睡姿,你是哪一种?
  3. TypeError: Object of type 'float32' is not JSON serializable
  4. 两个datatable之间的复制
  5. 对 js 高程 Preflighted Reqeusts 的理解
  6. CentOS忘记普通用户密码解决办法
  7. windows内核初窥(二)-----系统机制
  8. Qt在Mac系统下添加alias到IncludePath中
  9. IDEA如何设置鼠标滚轮调整代码大小
  10. haversine根据经纬度算距离
  11. 计算机软件企业账务处理,企业购买软件会计上如何处理
  12. windows禅道环境搭建
  13. redis缓存雪崩解决方案六种
  14. AppSpider:Xposed+JustTrustMe关闭SSL证书验证
  15. win10用win7的图片查看器
  16. 好站推荐-四个在线识别字体网站,从此不在为找字体烦恼
  17. String类的intern方法学习
  18. GuzzleHttp使用
  19. 分享一个查询快递物流单号的方法
  20. 数据可视化系列-05数据分析报告

热门文章

  1. 力扣leetcode之Java刷题121买卖股票的最佳时机
  2. 趋势交易和均值回归交易——哪个更好?
  3. MinMaxScaler 中scaler.inverse_transform不能反归一化正确的数据
  4. Java程序员不得不看的38本书
  5. windows 10右下角的时间显示带上星期
  6. pyqt5界面设计中八位十六进制颜色码说明
  7. QT应用编程: 调用系统语音引擎完成文字转语音播报
  8. 网络透视技术资料及学习笔记
  9. Java实现 LeetCode 223 矩形面积
  10. 使用XShell、XFTP连接虚拟机或者服务器教程