DS1302是DALLAS公司的一个时钟芯片,能设置秒、分钟、小时、月、星期、年,且年可以设置到2100年。有时钟/日历寄存器还有31*8位的额外数据暂存寄存器(RAM),可以存储对时间的修正参数或者初始化的标志(前提是DS1302要外接备用电源),如果主机掉电后重新上电时读取RAM中的初始化标志为1的话就不对DS1302初始化了。
说到备用电源,可以用3.3v的锂电池或者电源掉电时间短的话(几小时或一天)则可以使用大电容(0.1F以上)供电,只是貌似电容体积太大。
DS1302是通过三根线控制读写数据的,RST/SCL/IO.
RST:复位线,所有数据的读写,都需要保持RST为1,为0时就会终止当前的数据操作。
SCL:时钟线,提供数据操作的同步时钟。
写入数据时,写入数据在SCL=0时可以改变而在SCL=1时要保持不变,即数据会在SCL的上升沿写入到DS1302。数据传输是低位在前,高位在后。
读取数据时,在SCL=1变为SCL=0之后就可以读取数据(注:在写完寄存器后的一个下降沿就可以读取数据),即数据会在SCL的下降沿出现到IO数据线上。同样数据也是低位在前高位在后。
IO:数据线,要发送的八位数据,要从最低位一次移到IO数据线上。
时钟/日历寄存器:
秒 :
1000..R/W是寄存器地址和读写控制位,R/W为1为读,为0为写。后面是寄存器里的读写数据,均是以二进制的BCD码存在的。BCD码,0-9对应0000-1001,十位对应10sec,如59对应数据为,CH1011001。下面几个寄存器数据格式亦是如此。CH=1,代表晶振停振,CH=0,代表晶振起振,时钟要工作的话都需要起振的。
分 :
小时 :
bit7控制是1为12小时制,为0是24小时制,bit5为1则选择12小时下的PM,为0则是选择24小时的20-23小时段。
日 :
月 :
星期 :
年 :
CONTROL :
WP写保护位,写入时要置WP=0
还有涓流充电器寄存器,控制锂电池的充电电流。
DS1302的突发模式是连续读写寄存器,时钟/日历的7个寄存器是必须一下读完的,而其他的寄存器没必要一下读完。
读写时序,贴张图,详见DS1302的资料手册。
突发模式的读写没写,连续读写和普通读写就是控制指令的bit5-bit1全为1,bit6控制连续读写时钟/日历或RAM。
控制器:stc89c52
8位8段共阴数码管,78LS138控制位,74HC573控制数码管的各段,贴上电路图。
下面贴上DS1302的普通读写程序:
/*****************************************************************
*********** Name: DS1302
*********** Date: 2014/12/25
*********** Com: FairSun
*********** LOL
******************************************************************/
#include <reg51.h>
#include <intrins.h> //使用_nop_();
sbit SCL = P1^6;
sbit IO = P3^5;
sbit RST = P1^7;
#define H12_24 0x80 //0b1000 0000 bit7为1是12小时
#define AM_PM 0x20 //在12小时模式下,bit5为1则选中了PM,在24小时模式下,为1则选中了20-24小时段
#define CH 0x00 //sec设置的最高位,为0则晶振起振,为1则晶振不起振
const unsigned char smg_dp_yin[ 16 ] = {0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xef,
0xf7, 0xfc, 0xb9, 0xde, 0xfb, 0xf1};//0. 1. 2. 3......f.
//共阴极,显示小数点
//不显示小数点: smg_dp_yin[x] | 0x80
//共阳极显示小数点: ~smg_dp_yin[x]
//共阳极不显示小数点: ~(smg_dp_yin[x] | 0x80)
const unsigned char smg_8_pos[ 8 ] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; //对应P20,P21,P22,高位都为1,则与的时候P2的其他位不变
const unsigned char smg_sum = 8; //8位数码管
unsigned char smg_8_data[ 8 ] = { 0 };
struct HMS{
unsigned char hour;
unsigned char min;
unsigned char sec;
};
struct MD{
unsigned char month;
unsigned char date; //一月的几日
};
struct YD{
unsigned char year;
unsigned char day; //星期几
};
struct ALLDATE{
struct YD yd;
struct MD md;
struct HMS hms;
};
void per_init( void );
void delay_xms( unsigned int );
//void Timer0_init( void );
//void Timer0_server( void );
void ds1302_delay( void );
void Display_Time( struct ALLDATE allDate );
unsigned char DecToBCD(unsigned char mData);
unsigned char BCDToDec(unsigned char mData);
struct ALLDATE convertToSetTime(struct ALLDATE allDate);
struct ALLDATE convertToDisplayTime(struct ALLDATE allDate);
void ds1302_setTime(struct ALLDATE allDate);
struct ALLDATE ds1302_readTime( void );
void ds1302_writeByte(unsigned char mCommand, unsigned char mData);
unsigned char ds1302_readByte(unsigned char mCommand);
void main(void)
{
struct ALLDATE allDate = { {99, 4}, {12, 14}, {23, 59, 55} }; //设置时间:2099-12-14 星期4 23:59:55
per_init();
ds1302_setTime(allDate);
while( 1 )
{
allDate = ds1302_readTime();
Display_Time(allDate);
}
}
/************************************************************************
**函数名:void delay_xms( unsigned int x )
** 功能:延时xms
** 参数: 无
*************************************************************************/
void delay_xms( unsigned int x )
{
unsigned char j = 0;
while( x-- )
{
while( (j++) < 100 );
j = 0;
}
}
/************************************************************************
**函数名:void Per_init( void )
** 功能:各个外设初始配置
** 参数: 无
*************************************************************************/
void per_init( void )
{
P0 = 0xff;
P1 = 0xff;
P2 = 0xff;
P3 = 0xff;
}
/************************************************************************
**函数名:void Timer0_init( void )
** 功能:定时器0初始配置
** 参数: 无
*************************************************************************/
/*void Timer0_init( void )
{
TMOD |= 0x01; //设置定时器0的模式为16位
TH0 = ( 65536-46000 ) / 256;
TL0 = (65536-46000) % 256;
if( EA != 1 )
EA = 1;
ET0 = 1; //打开定时器0的中断
TR0 = 0; //定时器0暂停
}
*/
/************************************************************************
**函数名:定时器0的中断服务函数
** 功能:装初值
** 参数: 无
*************************************************************************/
/*void Timer0_server( void ) interrupt 1
{
TH0 = (65536-46000) / 256;
TL0 = (65536-46000) % 256;
} */
/************************************************************************
**函数名:void Display_Time(void)
** 功能:显示时间
** 参数: 无
*************************************************************************/
void Display_Time(struct ALLDATE allDate) //显示分钟
{
unsigned char pos;
unsigned char *pallDate = (unsigned char *)&allDate;
for(pos = 0; pos <= 7; pos+=2)
{
smg_8_data[pos] = *(pallDate+(pos>>1)) / 10 % 10;
smg_8_data[pos+1] = *(pallDate+(pos>>1))%10;
}
/*smg_8_data[0] = allDate.yd.year / 10 % 10;
smg_8_data[1] = allDate.yd.year%10;
smg_8_data[2] = allDate.hms.hour / 10 % 10;
smg_8_data[3] = allDate.hms.hour%10;
smg_8_data[4] = allDate.hms.min / 10 % 10;
smg_8_data[5] = allDate.hms.min%10;
smg_8_data[6] = allDate.hms.sec / 10 % 10;
smg_8_data[7] = allDate.hms.sec%10; */
for( pos = 0; pos < smg_sum; pos++ )
{
P2 &= 0xf8;
P2 |= smg_8_pos[pos];
P0 = smg_dp_yin[smg_8_data[pos]]&0x7f;
delay_xms(1);
}
}
void ds1302_delay( void )
{
int i;
for(i = 0; i < 1; i++)
{
_nop_();
}
}
/************************************************************************
**函数名:unsigned char DecToBCD(unsigned char mData)
** 功能:10进制转为BCD码
** 参数: unsigned char mData
*************************************************************************/
unsigned char DecToBCD(unsigned char mData)
{
unsigned char BCD = 0;
while(mData >= 10)
{
mData -= 10;
BCD ++;
}
BCD <<= 4;
BCD |= mData;
return BCD;
}
/************************************************************************
**函数名:unsigned char BCDToDec(unsigned char mData)
** 功能:BCD码转为10进制
** 参数: unsigned char mData
*************************************************************************/
unsigned char BCDToDec(unsigned char mData)
{
unsigned char Dec = 0;
Dec = mData & 0x0f; //取得最低位
mData = mData & 0x70; //剔除最高位和最低四位
Dec += mData>>1; //先左移1代表*2
Dec += mData>>3; //再左移3代表*8,所以总的相当于乘以10
return Dec;
}
/*
struct ALLDATE convertToSetTime(struct ALLDATE allDate)
{
struct ALLDATE mAllDate;
mAllDate.yd.year = ((allDate.yd.year/10)<<4) + (allDate.yd.year%10);
mAllDate.yd.day = allDate.yd.day;
mAllDate.md.month = ((allDate.md.month/10)<<4) + (allDate.md.month%10);
mAllDate.md.date = ((allDate.md.date/10)<<4) + (allDate.md.date%10);
mAllDate.hms.hour = H12_24 + AM_PM + ((allDate.hms.hour/10)<<4) + (allDate.hms.hour%10);
mAllDate.hms.min = ((allDate.hms.min/10)<<4) + (allDate.hms.min%10);
mAllDate.hms.sec = CH + ((allDate.hms.sec/10)<<4) + (allDate.hms.sec%10);
return mAllDate;
}
struct ALLDATE convertToDisplayTime(struct ALLDATE allDate)
{
struct ALLDATE mAllDate;
mAllDate.yd.year = ((allDate.yd.year/10)>>4)*10 + (allDate.yd.year%10);
mAllDate.yd.day = allDate.yd.day;
mAllDate.md.month = ((allDate.md.month/10)<<4) + (allDate.md.month%10);
mAllDate.md.date = ((allDate.md.date/10)<<4) + (allDate.md.date%10);
mAllDate.hms.hour = H12_24 + AM_PM + ((allDate.hms.hour/10)<<4) + (allDate.hms.hour%10);
mAllDate.hms.min = ((allDate.hms.min/10)<<4) + (allDate.hms.min%10);
mAllDate.hms.sec = CH + ((allDate.hms.sec/10)<<4) + (allDate.hms.sec%10);
return mAllDate;
} */
/************************************************************************
**函数名:struct ALLDATE convertToSetTime(struct ALLDATE allDate)
** 功能:将设置的时间转为BCD码
** 参数: struct ALLDATE allDate
*************************************************************************/
struct ALLDATE convertToSetTime(struct ALLDATE allDate)
{
unsigned char loop;
struct ALLDATE mAllDate;
unsigned char *pallDate = (unsigned char *)&allDate;
unsigned char *pmAllDate = (unsigned char *)&mAllDate;
for(loop = 0; loop <= 7; loop++)
{
*(pmAllDate+loop) = DecToBCD(*(pallDate+loop));
}
/*mAllDate.yd.year = DecToBCD(allDate.yd.year);
mAllDate.yd.day = DecToBCD(allDate.yd.day);
mAllDate.md.month = DecToBCD(allDate.md.month); //((allDate.md.month/10)<<4) + (allDate.md.month%10);
mAllDate.md.date = DecToBCD(allDate.md.date); //((allDate.md.date/10)<<4) + (allDate.md.date%10);
mAllDate.hms.hour = DecToBCD(allDate.hms.hour);//H12_24 + AM_PM + H12_24 + AM_PM + ((allDate.hms.hour/10)<<4) + (allDate.hms.hour%10);
mAllDate.hms.min = DecToBCD(allDate.hms.min); //((allDate.hms.min/10)<<4) + (allDate.hms.min%10);
mAllDate.hms.sec = CH + DecToBCD(allDate.hms.sec);//CH + ((allDate.hms.sec/10)<<4) + (allDate.hms.sec%10); */
return mAllDate;
}
/************************************************************************
**函数名:struct ALLDATE convertToDisplayTime(struct ALLDATE allDate)
** 功能:将读取的BCD码转为10进制要显示的数据
** 参数: struct ALLDATE allDate
*************************************************************************/
struct ALLDATE convertToDisplayTime(struct ALLDATE allDate)
{
unsigned char loop;
struct ALLDATE mAllDate;
unsigned char *pallDate = (unsigned char *)&allDate;
unsigned char *pmAllDate = (unsigned char *)&mAllDate;
for(loop = 0; loop <= 7; loop ++)
{
*(pmAllDate+loop) = BCDToDec(*(pallDate+loop));
}
/*mAllDate.yd.year = (((allDate.yd.year&0x80)>>4)*10) + BCDToDec(allDate.yd.year); //(((allDate.yd.year&0x80)>>4)*10) +
mAllDate.yd.day = BCDToDec(allDate.yd.day);
mAllDate.md.month = BCDToDec(allDate.md.month); //((allDate.md.month/10)<<4) + (allDate.md.month%10);
mAllDate.md.date = BCDToDec(allDate.md.date); //((allDate.md.date/10)<<4) + (allDate.md.date%10);
mAllDate.hms.hour = BCDToDec(allDate.hms.hour);//0x1f& H12_24 + AM_PM + ((allDate.hms.hour/10)<<4) + (allDate.hms.hour%10);
mAllDate.hms.min = BCDToDec(allDate.hms.min); //((allDate.hms.min/10)<<4) + (allDate.hms.min%10);
mAllDate.hms.sec = BCDToDec(allDate.hms.sec);//CH + ((allDate.hms.sec/10)<<4) + (allDate.hms.sec%10); */
return mAllDate;
}
/************************************************************************
**函数名:void ds1302_setTime(struct ALLDATE allDate)
** 功能:把时间写入到DS1302
** 参数: struct ALLDATE allDate
*************************************************************************/
void ds1302_setTime(struct ALLDATE allDate)
{
unsigned char loop;
unsigned char *pallDate = (unsigned char *)&allDate;
allDate = convertToSetTime(allDate);
ds1302_writeByte(0x8e, 0x00); //control为的最高位wp
for(loop = 0; loop <= 6; loop++)
{
ds1302_writeByte(0x8c-(loop<<1), *(pallDate+loop)); //sec
}
/*ds1302_writeByte(0x8e, 0x00); //control为的最高位wp
ds1302_writeByte(0x8c, allDate.yd.year); //year
ds1302_writeByte(0x8a, allDate.yd.day); //day
ds1302_writeByte(0x88, allDate.md.month); //month
ds1302_writeByte(0x86, allDate.md.date); //date
ds1302_writeByte(0x84, allDate.hms.hour); //hour
ds1302_writeByte(0x82, allDate.hms.min); //min
ds1302_writeByte(0x80, allDate.hms.sec); //sec */
}
/************************************************************************
**函数名:struct ALLDATE ds1302_readTime( void )
** 功能:从DS1302读取时间信息
** 参数: struct ALLDATE allDate
*************************************************************************/
struct ALLDATE ds1302_readTime( void )
{
unsigned char loop;
struct ALLDATE allDate;
unsigned char *pallDate = (unsigned char *)&allDate;
for(loop = 0; loop <= 6; loop++)
{
*(pallDate+loop) = ds1302_readByte(0x8d-(loop<<1));
}
/*allDate.yd.year = ds1302_readByte(0x8d); //year
allDate.yd.day = ds1302_readByte(0x8b); //day
allDate.md.month = ds1302_readByte(0x89); //month
allDate.md.date = ds1302_readByte(0x87); //date
allDate.hms.hour = ds1302_readByte(0x85); //hour
allDate.hms.min = ds1302_readByte(0x83); //min
allDate.hms.sec = ds1302_readByte(0x81); //sec */
allDate = convertToDisplayTime(allDate);
return allDate;
}
/************************************************************************
**函数名:void ds1302_writeByte(unsigned char mCommand, unsigned char mData)
** 功能:往DS1302写入一个字节
** 参数: unsigned char mCommand, unsigned char mData
*************************************************************************/
void ds1302_writeByte(unsigned char mCommand, unsigned char mData)
{
int loop;
RST = 0;
SCL = 0;
ds1302_delay();
RST = 1;
ds1302_delay();
for(loop = 0; loop < 8; loop++)
{
IO = (mCommand>>loop)&0x01;
ds1302_delay();
SCL = 1;
ds1302_delay();
SCL = 0;
ds1302_delay();
}
for(loop = 0; loop < 8; loop++)
{
IO = (mData>>loop)&0x01;
ds1302_delay();
SCL = 1;
ds1302_delay();
SCL = 0;
ds1302_delay();
}
RST = 0; //拉低停止数据传输
}
/************************************************************************
**函数名:unsigned char ds1302_readByte(unsigned char mCommand)
** 功能:从DS1302读取一个字节
** 参数: unsigned char mCommand
*************************************************************************/
unsigned char ds1302_readByte(unsigned char mCommand)
{
unsigned char loop = 0;
unsigned char readData = 0;
unsigned char temp = 0;
RST = 1; //必须置高
for(loop = 0; loop < 8; loop++)
{
IO = (mCommand>>loop)&0x01;
SCL = 1;
ds1302_delay();
SCL = 0;
}
for(loop = 0; loop < 8; loop++)
{
temp = IO;
SCL = 1;
ds1302_delay();
SCL = 0;
readData += (temp<<loop);
}
RST = 0; //拉低停止数据传输
return readData;
}