实时时钟芯片DS1307的使用及驱动代码

DS1307实时时钟芯片的介绍及驱动代码

目录

一、DS1307是什么?

二、DS1307的功能

三、DS1307的寄存器

四、代码

1.读出数据

2.写入数据

3.时间初始化设置

4.获取当前时间

五、注意事项

总结


一、DS1307是什么?

DS1307是一款基于IIC总线接口的实时时钟芯片,可以独立于MCU工作,芯片具有备用电源自动切换功能,可以在主电源掉电或其他一些恶劣环境下保证系统时钟的准确。

二、DS1307的功能

  1. DS1307具有产生时、分、秒、日、月、年等功能,闰年可自动调整,日历和时钟数据以BCD码的方式存放在片内的寄存器上。
  2. 片内集成了56字节的具有掉电后电池保持的RAM数据存储器,可以用来保存一些关键数据,
  3. 芯片具有掉电检测和自动切换电池供电功能,当DS1307靠后备电池维持工作时,拒绝CPU对其的读出和写入操作。

三、DS1307的寄存器

DS1307片内有多个时间保存寄存器,单片机就是通过读取这些寄存器得到时间和日期相关的数据的,其中有8个寄存器专门用来存储时间信息,另外56个字节的RAM可以供用户自由使用。

  1. 时间和日历信息在时间保存寄存器上的存放是以BCD码的形式存放的,以分钟寄存器为例,分的十位存放寄存器的高四位,分的个位存放在寄存器的低四位。
  2. 日期和星期寄存器的值会在每天的午夜递增,我们需要在程序中指定星期与星期寄存器的对应关系,也就是说把星期寄存器值为1时定义为星期一,那么当读取的值为1时就应当是星期日。
  3. 寄存器0(地址00h)的第7位是时钟停止位CH。当这一位置1时,时间振荡器会被禁止,该位清零时,振荡器会使能。
  4. 芯片在第一次上电时,时间和日期会被复位成:01月01日00年、星期01、00时00分00秒,秒寄存器的CH位会被设定为1。我们在对时间值进行设定时,需将CH位清零以使能振荡器。
  5. DS1307可以运行在12小时模式或24小时模式。小时寄存器的bit6是定义12小时或24小时模式选择位。当该位置1时,时钟被定义为12小时模式,清零时为24小时模式。
  6. DS1307可以设定为12小时模式下,小时寄存器的bit5是AM/PM位,其值为0时表示AM,为1时表示PM;在24小时模式下bit5是20小时位(20-23)。

四、代码

1.读出数据

/*
*********************************************************************************************************
*	函 数 名: uint8_t DS1307_Read(uint8_t address)
*	功能说明: 向DS1307寄存器读取数据
*	形    参:寄存器地址
*	返 回 值: 读出的数据
*********************************************************************************************************
*/
uint8_t DS1307_Read(uint8_t address)
{
	uint8_t dat;	
	i2c_Start();
	i2c_SendByte(0xD0);//发送设备地址,写指令
	i2c_WaitAck();
	i2c_SendByte(address);//发送寄存器地址
	i2c_WaitAck();
	i2c_Stop();
	i2c_Start();//重新启动IIC总线
	i2c_SendByte(0xD1);	//发送设备地址,读指令
	i2c_WaitAck();
	dat=i2c_ReadByte(); //读一个字节数据
	i2c_NAck();	
	i2c_Stop();
	return dat;
}

2.写入数据

/*
*********************************************************************************************************
*	函 数 名: DS1307_Wirte(uint8_t address , uint8_t dat)
*	功能说明: 向DS1307寄存器写数据
*	形    参:address:寄存器地址,dat:要写入的数据
*	返 回 值: 无
*********************************************************************************************************
*/
void DS1307_Wirte(uint8_t address , uint8_t dat)
{ 
	i2c_Start();
	i2c_SendByte(0xD0);//发送设备地址,写指令
	i2c_WaitAck();
	i2c_SendByte(address);//发送寄存器地址
	i2c_WaitAck();
	i2c_SendByte(dat);//写一个字节数据
	i2c_WaitAck();
	i2c_Stop();	
}

3.时间初始化设置

/*
*********************************************************************************************************
*	函 数 名: void DS1307_Init_Time(void)
*	功能说明: 第一次上电时,需要初始化时间,初始化一次后就不必重复初始化
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void DS1307_Init_Time(void)
{
	if(DS1307_Read(FLAG_ADDR)!=FLAG_VAL)//如果未初始化,执行初始化时间
	{
		DS1307_Set_Time(2023,2,16,19,02,00,4);//2023年2月16日 17:50:00 星期四
		printf("时间初始化完成,flag=%d\r\n",DS1307_Read(FLAG_ADDR));
	}	else{
		printf("时间已初始化过,flag=%d\r\n",DS1307_Read(FLAG_ADDR));
	}
}
//时间初始化设置
void DS1307_Set_Time(uint16_t year,uint8_t mon,uint8_t day,uint8_t hour,uint8_t min,uint8_t sec,uint8_t week)
{
	year-=2000;//年默认2000年开始
	if(year > 100) year = 0;
	
	//十进制转为BCD码
	year = ((year /10) << 4) + year %10;
	mon  = ((mon  /10) << 4) + mon  %10;
	day  = ((day  /10) << 4) + day  %10;
	week = ((week /10) << 4) + week  %10;
	hour = ((hour /10) << 4) + hour %10;
	min  = ((min  /10) << 4) + min  %10;
	sec  = ((sec  /10) << 4) + sec  %10;
	
	//写入寄存器,同时标记一个地址
	DS1307_Wirte(FLAG_ADDR,FLAG_VAL);   //写入已经设置时间标志		
	DS1307_Wirte(0x00,sec);    //设置秒
    DS1307_Wirte(0x01,min);    //设置分
    DS1307_Wirte(0x02,hour);   //设置时
    DS1307_Wirte(0x03,week);   //设置周
    DS1307_Wirte(0x04,day);    //设置日
    DS1307_Wirte(0x05,mon);    //设置月	
    DS1307_Wirte(0x06,year);   //设置年		
}

4.获取当前时间

//获取当前时间
void Get_Now_Time(void)
{
	uint8_t sec,min,hour,week,day,mon,year;
	uint8_t i;
	
	sec  = DS1307_Read(0x00);
	min  = DS1307_Read(0x01);
	hour = DS1307_Read(0x02);
	week = DS1307_Read(0x03);	
	day  = DS1307_Read(0x04);
	mon  = DS1307_Read(0x05);
	year = DS1307_Read(0x06);
	
	//BCD码转十进制
	date_time.sec  = (sec/16)*10 + sec%16;
	date_time.min  = (min/16)*10 + min%16;
	date_time.hour = (hour/16)*10 + hour%16;
	date_time.day  = (day/16)*10  + day%16;
	date_time.mon  = (mon/16)*10  + mon%16;
	date_time.year = (year/16)*10 + year%16 + 2000;
	date_time.week = (week/16)*10 + week%16;   			
}

五、注意事项

  1. DS1307的工作电压为4.5V-5.5V供电。
  2. I2C总线控制DS1307,用GPIO模拟I2C时序即可。
  3. 时间配置:直接把时间值写入0x00~0x06的时间寄存器。
  4. 时间读取:直接读取0x00~0x06的时间寄存器即可。
  5. 读取时间时发现未走时可能是00h 地址的寄存器第7 位为1,此位为1则芯片未开始工作,即时钟未走时,记得首次上电时把该位清零。
  6. 首次上电设置时间后不必每次上电都再次初始化一下时间,停电后有备用电池,此时不必重写时间单元。

总结

本文简单介绍了DS1307实时时钟芯片的使用,提供了DS1307的驱动程序代码,方便首次使用DS1307的初学者们学习和参考。

物联沃分享整理
物联沃-IOTWORD物联网 » 实时时钟芯片DS1307的使用及驱动代码

发表评论