DS3231时钟芯片全解析——概况,性能,MCU连接,样例代码

DS3231概述:

数据:

DS3231是一个超高精度I2C实时时钟芯片,带有集成的温度补偿晶振。误差范围:温度范围为0摄氏度到40摄氏度(±2PPM),温度范围为-40摄氏度到85摄氏度(±3.5PPM,每天±0.432秒)。包含时钟(24小时格式或12小时格式)、日历(年,月,日,星期)、两个可编程时间报警和一个可编程方波输出。

供电:

DS3231采用两组供电,一组主电,由外部供电(2.3V~5.5V),一组备电,一般由纽扣电池供电。当主电存在时,由主电供电,当主电不存在时由备电供电。

功能:

DS3231,通过内部带有温补的晶振自动对时间进行计数,对月末日期进行调整,以及闰年矫正。MCU可对其时间日期进行设置及读取,显示正确的当前时间。

连接:

与MCU通过标准I2C总线进行连接(注意,非标准I2C设备会占用I2C总线全部设备地址,导致标准设备不可用。),多个标准I2C设备可连接到同一条I2C总线上。

DS3231型号说明:

DS3231主要有两种型号,一种是16pin的DS3231SN,一种是8pin的DS3231MZ。主要是提醒,8pin的DS3231MZ,守时精度为±5PPM。

DS3231引脚说明:

引脚 名称 功能
1 32kHz 32.768kHz输出。开漏输出,需要外接上拉电阻。可在任何电源上工作,不使用需保持开路。
2 VCC 初级供电引脚。需使用0.1uF~1uF电容解耦,不使用请接地。
3 INT/SQW 主动下拉中断或方波输出。开漏输出,需要外接5.5V以下的上拉电阻。由多功能引脚控制寄存器的INTCN位决定。
4 RST 低电平复位引脚。同时可指示VCC和VPF的大小。VCC<VPF,引脚低电平;VCC>VPF,引脚高电平。不使用悬空。
5~12 N.C. 无连接,必须接地。
13 GND 电源接地。
14 VBAT 备用电源输入。需使用0.1uF~1uF电容解耦,不使用请接地。不会对VCC反向充电。
15 SDA I2C串行数据输入输出引脚。
16 SCL I2C串行时钟输入引脚。

DS3231电气性能:

V~PF~断电电流,VCC小于该电流时且小于VBAT时,由VBAT供电。

保持电流1uA,读取写入电流150uA,温度转换(64s周期)电流650uA,数据保持(关闭晶振)电流100nA。

DS3231电源控制:

DS3231对存储设备的电池消耗进行了优化,在第一次安装电池时,内部晶振不会启动 ,直到VCC超过上述VFP数值时,或将有效的I2C地址写入时,在1s内,晶振启动。大约2秒,设备进行测温,并应用于补偿,测温周期为64秒。晶振在激活后一直有效。

DS3231 MCU连接:

如图所示:

左侧为MCU接口,SCL和SDA接上拉电阻R~PU~,R~PU~取值可为10k,RST引脚可接MCU,如不使用,可悬空。

右侧VCC和VBAT各需要一个去耦电容,==其中VBAT的去耦电容如果无外部供电时不会进行读写操作,则可以取消。==去耦电容大小0.1uF~1uF。~~INT~~/SQW和32kHz接上拉电阻,如不使用,均可悬空,其中32kHz引脚输出32.768kHz方波可作为单片机时钟源进行精确延时。

DS3231寄存器定义:

DS3231设备地址:0xD0

时间寄存器:

  • 寄存器读取长度超过12h,则超过部分从00h开始。读取指针指向00h时,外部寄存器数值自动与内部寄存器同步。
  • 在数据读写时复位,则数据会丢失。
  • 时间数据和其他实时时钟芯片一样使用二进制编码的十进制(BCD)格式。
  • 小时寄存器的第6位为12/24小时格式选择位,第5位为AM/PM标志位,0为AM,1为PM。
  • 月份寄存器的第七位为世纪位。

报警寄存器:

报警间隔设置寄存器:

注意报警1秒钟匹配时警报,报警2分钟匹配时警报。

  • DS3231包含两个时间/日期报警。
  • 07h到0Ah为报警1时间;0Bh到0Dh为报警2时间。
  • 通过INTCN和A1IE和A2IE控制INT/SQW引脚输出。
  • 报警可编程为每隔1秒、1分钟、1小时、1天、或日期重复。
  • DY/DT用于设置是日期还是星期。
  • 当RTC寄存器的值与报警寄存器设置匹配时,相应的警报标志"A1F"或"A2F"位被设置为1。如果相应的警报中断使能"A1IE"或"A2IE"也被设置为1,并且INTCN位设置为1,则激活INT/SQW信号。时间和日期寄存器的每秒匹配一次。

控制寄存器:

  • BIT 7:启动晶振控制位。为0时启动晶振;为1时当VCC供电时晶振启动,当VBAT供电时关闭晶振。默认为1,首次通电时清0。
  • BIT 6:电池供电方波使能。条件苛刻,用处不大。
  • BIT 5: 转换温度控制位。设为1,强制更新一次温补。使用前先检查BSY位,避免与64s周期转换冲突。温补转换完成,BIT5和BSY位自动复位为0。
  • BIT 4 和 BIT 3:控制方波输出频率。方波启用时可用。
  • BIT 2:方波报警控制位。当RTC寄存器的值与报警寄存器设置匹配时,相应的警报标志"A1F"或"A2F"位被设置为1。如果相应的警报中断使能"A1IE"或"A2IE"也被设置为1,并且INTCN位设置为1,则激活INT/SQW信号。时间和日期寄存器的每秒匹配一次。
  • BIT 1:报警2中断使能,VCC上电清0。
  • BIT 0:报警1中断使能,VCC上电清0。

状态寄存器:

  • BIT 7:晶振停止标志位。为1时表示晶振已停止。
  • BIT 3:启用32.768kHz控制位。
  • BIT 2:温补操作状态位,为1时表示正在温度转换。
  • BIT 1:报警2报警标志位。该位为0时,同时A2IE为1,INTCN为1,此时当Alarm2时间匹配时才会触发 INT/SQW引脚的主动下拉中断(如果中断触发后,需要重新将其清0,才可以再次触发中断。)。
  • BIT 0:报警1报警标志位。该位为0时,同时A1IE为1,INTCN为1,此时当Alarm1时间匹配时才会触发 INT/SQW引脚的主动下拉中断(如果中断触发后,需要重新将其清0,才可以再次触发中断。)。
  • BIT 1和BIT 0有1,则INT/SQW引脚为低电平,都为零则为低电平。

老化偏置寄存器:

  • 二进制补码,调整电容值以进一步校准时钟。
  • 一般,25℃时,最小调整量为0.1ppm。

温度寄存器:

  • 温度寄存器为10bit,分辨率为0.25℃。使用二进制补码形式。上8位为整数部分在11h,下2位为小数部分在12h。例如00011001 01b=+25.25摄氏度,即25+0.25*1。

DS3231寄存器读写:

DS3231可在标准模式100kHz和快速模式400kHz下工作。

写时序:(写入的寄存器地址,后跟数据)

读时序:(写入的寄存器地址,再重新开启I2C通讯,再跟设备读取地址)

DS3231注意事项:

  • DS3231封装包含石英音叉晶体。可以使用拾取-贴装设备但是必须谨慎小心,以确保避免过度冲击。避免使用超声波清理,以免损坏晶体。
  • 除非封装与信号线之间有地层隔开,否则避免在器件下面走信号线。所有N.C.(无连接)引脚必须接地。
  • 潮湿敏感封装出厂时采用防潮包装。必须遵循封装标签上列出的操作说明,以防止回流焊过程中损坏器件。
  • 潮湿敏感器件(MSD)的分类和回流焊温度曲线请参考IPC/JEDEC J-STD-020标准。允许的回流焊次数最多2次。

DS3231样例代码: (基于HC32L130)

ds3231.h

#ifndef __DS3231_H__
#define __DS3231_H__


/* Includes ------------------------------------------------------------------*/

#include "gpio.h"


/* Exported types ------------------------------------------------------------*/

typedef struct
{
		uint8_t yearH;			//年千百位
		uint8_t yearL;			//年 
		uint8_t month;			//月 			
		uint8_t date;		  //日 
		uint8_t hour;		  //时 
		uint8_t minute;		//分
		uint8_t second;		//秒
		uint8_t week;		  //周 
}_calendar_obj;

extern _calendar_obj calendar;	//日历结构体

/* DS3231 地址定义 */
/* ADDR Pin Conect to VSS */
#define 	 DS3231_ADDR    		  0xD0
#define    DS3231_ADDR_WRITE    0xD0
#define    DS3231_ADDR_READ     0xD1

/* DS3231寄存器地址 */
typedef enum
{
    DS3231_SECOND = 0x00,    //秒
		DS3231_MINUTE = 0x01,    //分
		DS3231_HOUR   = 0x02,    //时
		DS3231_WEEK   = 0x03,    //星期
		DS3231_DAY    = 0x04,    //日
		DS3231_MONTH  = 0x05,    //月
		DS3231_YEAR   = 0x06,    //年
		/* 闹铃1 */          
		DS3231_ALARM1SECOND   = 0x07,    //秒
		DS3231_ALARM1MINUTE   = 0x08,    //分
		DS3231_ALARM1HOUR     = 0x09,    //时
		DS3231_ALARM1DATE  		= 0x0A,    //星期/日
		/* 闹铃2 */
		DS3231_ALARM2MINUTE 	= 0x0b,    //分
		DS3231_ALARM2HOUR     = 0x0c,    //时
		DS3231_ALARM2DAY     = 0x0d,    //星期/日
		
		DS3231_CONTROL        = 0x0e,    //控制寄存器
		DS3231_STATUS         = 0x0f,    //状态寄存器
		BSY                 	= 2,       //忙
		OSF                		= 7,       //振荡器停止标志
		DS3231_XTAL         	= 0x10,    //晶体老化寄存器
		DS3231_TEMPERATUREH 	= 0x11,    //温度寄存器高字节(8位)
		DS3231_TEMPERATUREL 	= 0x12,    //温度寄存器低字节(高2位) 
} DS3231_CMD;																				
																																								
/* Exported functions ------------------------------------------------------- */

void DS3231_Init(void);		

en_result_t I2C_DS3231_WriteCmd(M0P_I2C_TypeDef* I2CX,DS3231_CMD pu8Addr, uint8_t pu8Data);
en_result_t I2C_MasterRead_DS3231Data(M0P_I2C_TypeDef* I2CX,DS3231_CMD pu8Addr,uint8_t*pu8Data,uint32_t u32Len);

void I2C_DS3231_SetTime(uint8_t year,uint8_t month,uint8_t day,uint8_t week,uint8_t hour,uint8_t minute,uint8_t second);
void I2C_DS3231_ReadTime(void);
void I2C_DS3231_SetAlarm_1(boolean_t en,uint8_t date,uint8_t hour,uint8_t minute,uint8_t second);
void I2C_DS3231_SetAlarm_2(boolean_t en,uint8_t hour,uint8_t minute);
uint8_t I2C_DS3231_ReadTime_Hour(void);
uint8_t I2C_DS3231_ReadTime_Minute(void);

uint8_t I2C_DS3231_getTemperature(void);

#endif /* __DS3231_H__ */

ds3231.c

#include "ds3231.h"
#include "i2c.h"
#include "bsp_delay.h"


// BCD(8421)转DEC
uint8_t BCD_DEC(uint8_t val)
{
	uint8_t i;
	i= val&0x0f;
	val >>= 4;
	val &= 0x0f;
	val *= 10;
	i += val;    
	return i;
}

// DEC转BCD(8421)
uint8_t DEC_BCD(uint8_t val)
{
  uint8_t i,j,k;
  i=val/10;
  j=val%10;
  k=j+(i<<4);
  return k;
}

//DS3231初始化
void DS3231_Init(void)
{
    I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_CONTROL,0x04);    	//闹钟中断允许,初始化禁用闹钟1闹钟2
    I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_STATUS,0x00);     	//32KHZ输出禁止,闹钟标志位清零
}

// DS3231写命令函数,只进行写命令操作
en_result_t I2C_DS3231_WriteCmd(M0P_I2C_TypeDef* I2CX,DS3231_CMD pu8Addr, uint8_t pu8Data)
{
		en_result_t enRet = Error;
		//超时重启值
		uint32_t u32TimeOut = 0x00FFFFu;
    uint8_t sendCount = 0, u8State = 0;
		I2C_SetFunc(I2CX,I2cStop_En);          ///发送停止条件
		I2C_ClearIrq(I2CX);
    I2C_SetFunc(I2CX,I2cStart_En);										 ///发送起始条件
		while(1)
		{
				while(0 == I2C_GetIrq(I2CX))
				{
						while(0 == I2C_GetIrq(I2CX))
						{		
								//超时I2C还未启动
								if(0 == u32TimeOut--)
								{
										//软重启
										NVIC_SystemReset();
								}
						}
				}
				u8State = I2C_GetState(I2CX);
				switch(u8State)
				{
						case 0x08:                                 ///已发送起始条件
								I2C_ClearFunc(I2CX, I2cStart_En);
								I2C_WriteByte(I2CX, DS3231_ADDR_WRITE);  ///发送设备地址+W写标志0
								break;
						case 0x18:                                 ///已发送SLW+W,已接收ACK
						case 0x28:                                 ///已发送I2Cx_DATA中的数据,已接收ACK
								switch(sendCount)
								{
										case 0:
												I2C_WriteByte(I2CX,pu8Addr);		 ///发送地址
												break;
										case 1:
												I2C_WriteByte(I2CX,pu8Data);		 ///发送数据
												break;
								}
								sendCount++;
								break;
						case 0x20:                                 ///已发送SLW+W,已接收非ACK
								break;
						case 0x30:                                 ///已发送I2Cx_DATA中的数据,已接收非ACK,将传输一个STOP条件
								I2C_SetFunc(I2CX,I2cStop_En);          ///发送停止条件
								break;
						case 0x58:                                 ///< 已接收到最后一个数据,NACK已返回
                I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
                break;
            case 0x38:                                 ///< 在发送地址或数据时,仲裁丢失
                I2C_SetFunc(I2CX,I2cStart_En);         ///< 当总线空闲时发起起始条件
                break;
            case 0x48:                                 ///< 发送SLA+R后,收到一个NACK
                I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
                I2C_SetFunc(I2CX,I2cStart_En);         ///< 发送起始条件
                break;
						default:
								break;
				}            
				if(sendCount>2)
				{
						I2C_SetFunc(I2CX,I2cStop_En);              ///此顺序不能调换,出停止条件
						I2C_ClearIrq(I2CX);
						break;
				}
				I2C_ClearIrq(I2CX);                            ///清除中断状态标志位
		}
		enRet = Ok;
    return enRet;
}
 
// 主机读取数据函数,只进行读数据操作
en_result_t I2C_MasterRead_DS3231Data(M0P_I2C_TypeDef* I2CX,DS3231_CMD pu8Addr,uint8_t *pu8Data,uint32_t u32Len)
{
		en_result_t enRet = Error;
		//超时重启值
		uint32_t u32TimeOut = 0x00FFFFu;
    uint8_t u8State=0;
    uint8_t receiveCount=0;
    uint8_t sendAddrCount=0;
		I2C_SetFunc(I2CX,I2cStop_En);          ///发送停止条件
		I2C_ClearIrq(I2CX);
    I2C_SetFunc(I2CX,I2cStart_En);										 ///发送起始条件

    while(1)
    {
        while(0 == I2C_GetIrq(I2CX))
        {		
						//超时I2C还未启动
						if(0 == u32TimeOut--)
						{
								//软重启
								NVIC_SystemReset();
						}
				}
        u8State = I2C_GetState(I2CX);
        switch(u8State)
        {
            case 0x08:                                 ///< 已发送起始条件,将发送SLA+W
								sendAddrCount++;
								I2C_ClearFunc(I2CX,I2cStart_En);
								I2C_WriteByte(I2CX,DS3231_ADDR_WRITE); 
                break;
            case 0x18:                                 ///< 已发送SLA+W,并接收到ACK
                I2C_WriteByte(I2CX, pu8Addr); 					 ///< 读取寄存器位置
                break;
            case 0x28:                                 ///< 已发送数据,接收到ACK, 此处是已发送从机内存地址u8Addr并接收到ACK
								I2C_SetFunc(I2CX,I2cStart_En);
                break;
            case 0x10:                                 ///< 已发送重复起始条件
                I2C_ClearFunc(I2CX,I2cStart_En);
								I2C_WriteByte(I2CX,DS3231_ADDR_READ);///< 发送SLA+R,开始从从机读取数据	
                break;
            case 0x40:                                 ///< 已发送SLA+R,并接收到ACK
                if(u32Len>=1)
                {
                    I2C_SetFunc(I2CX,I2cAck_En);       ///< 使能主机应答功能
                }
                break;
            case 0x50:                                 ///< 已接收数据字节,并已返回ACK信号
                pu8Data[receiveCount] = I2C_ReadByte(I2CX);
								receiveCount++;
                if(receiveCount==u32Len)
                {
                    I2C_ClearFunc(I2CX,I2cAck_En);     ///< 已接收到倒数第二个字节,关闭ACK应答功能
                }
                break;
            case 0x58:                                 ///< 已接收到最后一个数据,NACK已返回
								I2C_ClearFunc(I2CX,I2cStart_En);
                I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
								I2C_SetFunc(I2CX,I2cStart_En);
                break;
            case 0x38:                                 ///< 在发送地址或数据时,仲裁丢失
                I2C_SetFunc(I2CX,I2cStart_En);         ///< 当总线空闲时发起起始条件
                break;
            case 0x48:                                 ///< 发送SLA+R后,收到一个NACK
                I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
                I2C_SetFunc(I2CX,I2cStart_En);         ///< 发送起始条件
                break;
            default:
                I2C_SetFunc(I2CX,I2cStart_En);         ///< 其他错误状态,重新发送起始条件
                break;
        }
        I2C_ClearIrq(I2CX);                            ///< 清除中断状态标志位
        if(receiveCount==u32Len)                                ///< 数据全部读取完成,跳出while循环
        {
                break;
        }
    }
    enRet = Ok;
    return enRet;
}
 
// DS3231设置时间日期
void I2C_DS3231_SetTime(uint8_t year,uint8_t month,uint8_t day,uint8_t week,uint8_t hour,uint8_t minute,uint8_t second)
{
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}
	
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_SECOND,DEC_BCD(second));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_MINUTE,DEC_BCD(minute));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_HOUR,DEC_BCD(hour));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_WEEK,DEC_BCD(week));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_DAY,DEC_BCD(day));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_MONTH,DEC_BCD(month));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_YEAR,DEC_BCD(year));
}	

// DS3231读取时间日期
void I2C_DS3231_ReadTime()
{
		uint8_t readTimeList[7]= {0};
    
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}

		I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_SECOND,readTimeList,7);
		
		calendar.yearH  = 20;			//年千百位
		calendar.yearL  = BCD_DEC(readTimeList[6]);			//年 
		calendar.month  = BCD_DEC(readTimeList[5]);			//月 			
		calendar.date   = BCD_DEC(readTimeList[4]);		  //日 
		calendar.hour   = BCD_DEC(readTimeList[2]);		  //时 
		calendar.minute = BCD_DEC(readTimeList[1]);			//分
		calendar.second = BCD_DEC(readTimeList[0]);			//秒
		calendar.week   = BCD_DEC(readTimeList[3]);		  //周 
}	

//DS3231设置Alarm_1
void I2C_DS3231_SetAlarm_1(boolean_t en,uint8_t date,uint8_t hour,uint8_t minute,uint8_t second)
{
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}

		if(en)
		{
				I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM1SECOND,DEC_BCD(second));
				I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM1MINUTE,DEC_BCD(minute));
				I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM1HOUR,DEC_BCD(hour));
				I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM1DATE,DEC_BCD(date));

				I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_CONTROL,&readData,1);
				readData |= 0x01;
				I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_CONTROL,readData);    	//复用引脚设置闹钟中断
		}
		else
		{
				I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_CONTROL,&readData,1);
				readData &= 0xFE;
				I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_CONTROL,readData);    	//复用引脚禁用闹钟中断
		}
}	

//DS3231设置Alarm_2
void I2C_DS3231_SetAlarm_2(boolean_t en, uint8_t hour, uint8_t minute)
{
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}
		
		//设置日期匹配寄存器A2M4位为1,即每日进行时分匹配
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM2DATE,0x80);
		//写入时分匹配数据
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM2MINUTE,DEC_BCD(minute));
		I2C_DS3231_WriteCmd(M0P_I2C0, DS3231_ALARM2HOUR,DEC_BCD(hour));

		if(en)
		{
				I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_CONTROL,&readData,1);
				readData |= 0x02;
				I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_CONTROL,readData);    	//复用引脚设置闹钟中断
		}
		else
		{
				I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_CONTROL,&readData,1);
				readData &= 0xFD;
				I2C_DS3231_WriteCmd(M0P_I2C0,DS3231_CONTROL,readData);    	//复用引脚禁用闹钟中断
		}
}	

// DS3231读取小时数据
uint8_t I2C_DS3231_ReadTime_Hour()
{
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}

		I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_HOUR,&readData,1);
		
		return readData;
}	

//DS3231读取分钟数据
uint8_t I2C_DS3231_ReadTime_Minute()
{   
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}

		I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_MINUTE,&readData,1);
		
		return readData;
}	

// 获取温度整数部分
uint8_t I2C_DS3231_getTemperature(void)
{
		uint8_t readData = 0x04;
		// DS3231忙则等待
		while((readData&0x04) > 0)
		{
			I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_STATUS,&readData,1);
		}

		I2C_MasterRead_DS3231Data(M0P_I2C0,DS3231_TEMPERATUREH,&readData,1);

		return readData;
}
相关推荐
长潇若雪8 分钟前
结构体(C 语言)
c语言·开发语言·经验分享·1024程序员节
Java Fans28 分钟前
嵌入式软件在电子烟开发中的应用
嵌入式硬件
DARLING Zero two♡42 分钟前
关于我、重生到500年前凭借C语言改变世界科技vlog.12——深入理解指针(2)
c语言·开发语言·科技·1024程序员节
独行soc1 小时前
#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶之Jenkins组件
安全·jenkins·安全威胁分析·1024程序员节·shodan
dawn1912282 小时前
Java 中的正则表达式详解
java·开发语言·算法·正则表达式·1024程序员节
黑不拉几的小白兔2 小时前
PTA L1系列题解(C语言)(L1_097 -- L1_104)
数据结构·算法·1024程序员节
环能jvav大师2 小时前
使用Ubuntu系统+VS Code开发STC51单片机
linux·c语言·开发语言·单片机·嵌入式硬件·ubuntu
小言从不摸鱼2 小时前
【Python】元组、字典与集合详解:数据容器的实战应用
人工智能·python·1024程序员节
魔法自动机3 小时前
Unity3D学习FPS游戏(3)玩家第一人称视角转动和移动
unity·1024程序员节·fps
q4725994513 小时前
UART通过DMA接收和发送,使用环形缓冲区,状态机的使用
stm32·单片机·嵌入式硬件