第18章实时时钟芯片应用•对于一个完善的单片机系统,经常需要对时间进行操作。例如,记录当前采集数据的时间、显示当前时间、设定关机时间等等。为了能够对时间进行控制,通常需要在硬件电路中集成实时时钟芯片。实时时钟芯片一般均内置了可编程的实时日历时钟,用于设定以及保存时间。其采用备份电池供电,在系统断电时仍可以工作,因此时间值不会丢失。另外,实时时钟芯片一般内置闰年补偿系统,计时很准确。实时时钟芯片的这些优点,使得其广泛应用于需要时间显示的测控系统或者手持式设备中。•本章以美国DALLAS公司推出实时时钟芯片DS1302为例,介绍实时时钟芯片的功能、控制指令以及时间的操作,并给出了相应的操作子函数供读者调用。本章最后通过一个具体的实例,讲解了如何使用51系列单片机来操作实时时钟芯片DS1302。18.1实时时钟芯片DS1302概述•DS1302是美国DALLASSemiconductor公司推出的一款实时时钟芯片。其以计时准确、接口简单、使用方便、工作电压范围宽和低功耗等优点,得到了广泛的应用。DS1302的主要特点如下:•DS1302采用3线串行接口,占用引脚少。•DS1302内部集成了可编程日历时钟,用户可以根据需要设置。•DS1302内部集成了31个字节的静态RAM。•DS1302的日历时钟可自动进行闰年补偿。•DS1302支持双电源供电,可以使用外部主电源和备份电源。•DS1302芯片具有对备份电池进行涓流充电功能,可有效长备份电池的使用寿命。18.1.1实时时钟芯片DS1302概述•实时时钟芯片DS1302引脚结构,如图所示。其中各个引脚功能如下所示。DS1302的引脚排列18.1.2实时时钟芯片DS1302日期操作•DS1302的日期操作主要用于对日期和时间相关的寄存器进行操作。实时时钟芯片DS1302与日期和时间有关的寄存器数据格式,如图所示。下面分别介绍各个寄存器含义:DS1302的日期数据格式18.1.3实时时钟芯片DS1302的控制操作•DS1302的控制操作用于写保护和充电控制。与控制有关的DS1302寄存器格式,如图所示。下面分别介绍各个寄存器含义:DS1302的控制数据格式18.1.4实时时钟芯片DS1302的RAM操作•DS1302的RAM操作用于读写片内的RAM存储器。实时时钟芯片DS1302的RAM定义,如图所示。A4~A0用于表示片内RAM单元地址,地址范围为00H~1EH,地址1FH为RAM多字节命令。DS1302的RAM定义18.1.5实时时钟芯片DS1302数据传输方式•实时时钟芯片DS1302为从器件,只由外部微控制器来控制数据传输。每次传送时由外部控制器向DS1302写入一个命令字节开始,然后是数据字节。DS1302的数据传输则可以采用单字节方式,或者多字节突发方式进行。多字节数据传输时序单字节数据传输时序18.2DS1302的控制子函数•DS1302通过RST、SCLK和I/O引脚和外部控制器进行通信。在程序中,需要首先声明接口引脚,示例如下:•sbitSCLK=P1^3;//声明接口引脚•sbitI_O=P1^4;•sbitRSTB=P1^5;•下面,给出在C51语言中,对实时时钟芯片DS1302进行操作的各个子函数,供读者使用。18.2.1复位子函数•复位子函数用于对实时时钟芯片DS1302进行硬件复位操作。在程序中,通过RSTB引脚赋值来进行复位操作。复位子函数程序代码示例如下:•voidResetDS1302()//复位子函数•{•SCLK=0;•RSTB=0;//复位•RSTB=1;•}18.2.2字节读取子函数•字节读取子函数用于读取实时时钟芯片DS1302的内部数据。在程序中,构造SCLK引脚时钟,通过IO引脚逐位读取DS1302返回的字节数据。字节读取子函数程序代码示例如下:•ucharReadByteDS1302()//字节读取子函数•{•uchari;•ucharRByte;•ucharTempByte;••RByte=0x00;//初始化•I_O=1;•for(i=0;i8;++i)//逐位读取字节数据•{•SCLK=1;//构造时钟•SCLK=0;•TempByte=(uchar)I_O;•TempByte=TempByte7;//移位•RByte=RByte1;•RByte|=TempByte;•}•returnRByte;//返回结果•}18.2.3字节写入子函数•字节写入子函数用于向实时时钟芯片DS1302写入寄存器地址或者数据。在程序中,构造SCLK引脚时钟,并通过I/O引脚逐位写入8位的字节数据。字节写入子函数程序代码示例如下:•voidWriteByteDS1302(ucharW_Byte)//字节写入子函数•{•uchari;•for(i=0;i8;++i)//循环逐位写入•{•I_O=0;•if(W_Byte&0x01)•I_O=1;•SCLK=0;//时钟操作•SCLK=1;•W_Byte=W_Byte1;//移位•}•}18.2.4年设置子函数•年设置子函数用于向实时时钟芯片DS1302的年寄存器写入年数据。在程序中,首先输入年数据,然后按照单字节数据传输方式写入年数据。年设置子函数程序代码示例如下:•voidSetYear()//年设置子函数•{•ucharyear;•printf(\nPleaseEntertheyear(0-99):);//输入年•scanf(%bx,&year);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x06);//年寄存器地址•WriteByteDS1302(year);//写入年•ResetDS1302();//复位DS1302•}18.2.5月设置子函数•月设置子函数用于向实时时钟芯片DS1302的月寄存器写入年数据。在程序中,首先输入月数据,然后按照单字节数据传输方式写入月数据。月设置子函数程序代码示例如下:•voidSetMonth()//月设置子函数•{•ucharmonth;•printf(\nPleaseEnterthemonth(1-12):);//输入月•scanf(%bx,&month);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x04);//月寄存器地址•WriteByteDS1302(month);//写入月•ResetDS1302();//复位DS1302•}18.2.6日设置子函数•日设置子函数用于向实时时钟芯片DS1302的日寄存器写入日数据。在程序中,首先输入日数据,然后按照单字节数据传输方式写入日数据。日设置子函数程序代码示例如下:•voidSetDate()//日设置子函数•{•uchardate;•printf(\nPleaseEnterthedate(1-31):);//输入日•scanf(%bx,&date);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x03);//日寄存器地址•WriteByteDS1302(date);//写入日•ResetDS1302();//复位DS1302•}18.2.7星期设置子函数•星期设置子函数用于向实时时钟芯片DS1302的星期寄存器写入星期数据。在程序中,首先输入星期数据,然后按照单字节数据传输方式写入星期数据。星期设置子函数程序代码示例如下:•voidSetDay()//星期设置子函数•{•ucharday;•printf(\nPleaseEntertheday(1-7):);//输入星期•scanf(%bx,&day);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x05);//星期寄存器地址•WriteByteDS1302(day);//写入星期•ResetDS1302();//复位DS1302•}18.2.8小时设置子函数•小时设置子函数用于向实时时钟芯片DS1302的小时寄存器写入小时数据。在程序中,首先输入小时数据,然后按照单字节数据传输方式写入小时数据。小时设置子函数程序代码示例如下:•voidSetHour()//小时设置子函数•{•ucharhour;•printf(\nPleaseEnterthehour(1-24):);//输入小时•scanf(%bx,&hour);•hour=hour&0x3f;//设置时钟为24小时方式•ResetDS1302();//复位DS1302•WriteByteDS1302(0x02);//小时寄存器地址•WriteByteDS1302(hour);//写入小时•ResetDS1302();//复位DS1302•}18.2.9分钟设置子函数•分钟设置子函数用于向实时时钟芯片DS1302的分钟寄存器写入分钟数据。在程序中,首先输入分钟数据,然后按照单字节数据传输方式写入分钟数据。分钟设置子函数程序代码示例如下:•voidSetMinute()//分钟设置子函数•{•ucharminute;•printf(\nPleaseEntertheminute(0-59):);//输入分钟•scanf(%bx,&minute);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x01);//分钟寄存器地址•WriteByteDS1302(minute);//写入分钟•ResetDS1302();//复位DS1302•}18.2.10秒设置子函数•秒设置子函数用于向实时时钟芯片DS1302的秒寄存器写入秒数据。在程序中,首先输入秒数据,然后按照单字节数据传输方式写入秒数据。秒设置子函数程序代码示例如下:•voidSetSecond()//秒设置子函数•{•ucharsecond;•printf(\nPleaseEnterthesecond(0-59):);//输入秒•scanf(%bx,&second);•ResetDS1302();//复位DS1302•WriteByteDS1302(0x00);//秒寄存器地址•WriteByteDS1302(second);//写入秒•ResetDS1302();//复位DS1302•}18.2.11写保护子函数•写保护子函数用于禁止修改实时时钟芯片DS1302内部寄存器的数据。在程序中,按照单字节数据传输方式向写保护控制寄存器写入0x80。写保护子函数程序代码示例如下:•voidDisableWrite()//写保护子函数•{•ResetDS1302();//复位DS1302•WriteByteDS1302(0x8e);//写保护控制寄存器•WriteByteDS1302(0x80);//禁止写入•ResetDS1302();//复位DS1302•}18.2.12写允许子函数•写允许子函数用于允许修改实时时钟芯片DS1302内部寄存器的数据。在程序中,按照单字节数据传输方式向写保护控制寄存器写入0x00。写允许子函数程序代码示例如下:•voidEnableWrite()//写允许子函数•{•ResetDS1302();//复位DS1302•WriteByteDS1302(0x8e);//写保护控制寄存器•WriteByteDS1302(0);//允许写入•ResetDS1302();//复位DS1302•}18.2.13充电控制子函数•充电控制子函数用于允许实时时钟芯片DS1302对备份电池进行充电操作。在程序中,按照单字节数据传输方式向涓流充电寄存器写入0xab。充电控制子函数程序代码示例如下:•voidCharge()//充电控制子函数•{•ResetDS1302();//复位DS1302•WriteByteDS1302(0x90);//涓流充电寄存器•WriteByteDS1302(0xab);//允许充电•ResetDS1302();//复位DS1302•}18.2.14初始化子函数•初始化子函数用于对实时时钟芯片D