DS1302是 DALLAS 公司推出的涓流充电时钟芯片,内含一个实时时钟/日历和31字节静态 RAM,可以通过串行接口与单片机进行通信,仅需三根 I/O线:复位(RST)、I/O数据线、串行时钟(SCLK),(补充一点小知识:一般来讲,无论是哪种同步通讯类型的串行接口,都是对时钟信号敏感的,而且一般数据写入有效是在上升沿,读出有效是在下降沿)。要想与ds1302通讯,就必须先了解它的控制字,
如图所示,控制字的最高有效位(位7)必须是逻辑1,如果它为0,则不能把数据写入到 DS1302中;位6:如果为0,则表示存取日历时钟数据,为1表示存取 RAM 数据;位5至位1(A4~A0):指示操作单元的地址;位0(最低有效位):如为0,表示要进行写操作,为1表示进行读操作。控制字总是从最低位开始输出。在控制字指令输入后的下一个SCLK 时钟的上升沿时,数据被写入 DS1302,数据输入从最低位(0位)开始。同样,在紧跟8位的控制字指令后的下一个 SCLK 脉冲的下降沿,读出 DS1302的数据,读出的数据也是从最低位到最高位。
程序还有些地方看不懂,就是关于写操作时CLK应该是上升沿,但此程序是下降沿,而且运行良好,改成上升沿反而不对了,很不理解,etc.
现在介绍下主要的几块程序:
void v_RTInputByte(uchar ucDa) //输入-写操作
{
uchar i;
ACC=ucDa;//待写数据送给ACC
for(i=8;i>0;i--)
{
if((ACC&0x01)==1) //ACC最后1位为1
T_IO=1;
else T_IO=0;//if((ACC&0x01)==0)
T_CLK=1;
T_CLK=0;//不是上升沿写吗?
ACC=ACC>>1;
}
}
uchar uc_RTOutputByte(void) //输出-读操作
{
uchar i,ACC;
ACC=0;//ACC清0
for(i=0;i<8;i++)
{
ACC=ACC>>1;
if(T_IO==1)
ACC=ACC|0x80;//ACC第1位置1
T_CLK=1;
T_CLK=0; //下降沿
}
return(ACC);//返回ACC
}
void v_W1302(uchar ucAddr,uchar ucDa) //指定地址写数据
{
T_RST=0;
T_CLK=0;
T_RST=1;
v_RTInputByte(ucAddr); //写地址
v_RTInputByte(ucDa); //写数据
T_CLK=1;
T_RST=0;
}
uchar uc_R1302(uchar ucAddr) //指定地址读数据
{
unsigned char ucDa,k; //BCD转换成16进制
k=0x00;
T_RST=0;
T_CLK=0;
T_RST=1;
v_RTInputByte(ucAddr);
ucDa=uc_RTOutputByte();
T_CLK=1;
T_RST=0;
k=ucDa/16;
ucDa=ucDa;
ucDa=ucDa+k*10;//16进制转化为10进制
return(ucDa);
}
以上就是对ds1302的给定地址读写操作了,下面是显示初始值的设定和记录时间子程序
void v_Set1302()//uchar *pSecDa) 设置初始时间值
{
uchar i,j;
uchar ucAddr=0x80; // 秒写地址
v_W1302(0x8e,0x00); // 控制命令,WP=0,写操作
for(i=0;i<7;i++) // 连续写入7个时间
{
j=ucCurtime[i]; // 代入初始时间
v_W1302(ucAddr,j); // 秒 分 时
ucAddr +=2; // 地址+2,因为都是两位数
}
v_W1302(0x8e,0x80); // 控制命令,WP=1,写保护
}
void v_Get1302() // 记录时间
{
uchar i;
uchar ucAddr=0x81; // 秒读地址
for (i=0;i<7;i++) // 连续读数据
{
ucCurtime[i]=uc_R1302(ucAddr);//格式为: 秒 分 时
ucAddr +=2;
}
}
然后是数码管显示内容和显示设置
void t2_10() //数码管段数字显示内容
{
unint k;
a[5]=temp1/10;
a[4]=temp1;
a[3]=temp/1000;
k=temp00;
a[2]=k/100;
k=k0;
a[1]=k/10;
a[0]=k;
}
void display2() //显示设置
{
t2_10();
wei_1(0x7f); //秒(两位)
duan_1(a[0]);
wei_1(0xbf);
duan_1(a[1]);
wei_1(0xdf);
duan_1(10);
wei_1(0xef);
duan_1(a[2]);
wei_1(0xf7);
duan_1(a[3]);
wei_1(0xfb);
duan_1(10);
wei_1(0xfd);
duan_1(a[4]);
wei_1(0xfe);
duan_1(a[5]);
wei_1(0xff);
}
然后是主程序
void main()
{
unint i,k;
for(i=0;i<7;i++) //将10进制转换成16进制
{
k=ucCurtime[i]/10;
ucCurtime[i]=ucCurtime[i];
ucCurtime[i]=ucCurtime[i]+16*k;
}
v_Set1302(); //时间初值
while(1)
{
v_Get1302(); //记录时间
temp1=ucCurtime[2]; //时
temp=ucCurtime[1]*100+ucCurtime[0]; //分+秒
display2(); //显示
}
}
这个程序是比较综合的除了中断没用到,其他的基本都用到了,其实若加进去整点报时或闹铃设置就更全面了,想着以后用1602做个时钟加进去这两个功能,试试吧。