电子说
DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时,且具有闰年补偿等多种功能。
P17:SCLK为时钟输入端。P23:I/O为串行数据输入输出端(双向)
P13:RST是复位
第一行:秒->因为秒的范围是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示个位,十位最大是5,所以三位即可。
第二行:跟上面一样;
第三行:7位:1为12小时制,0为24小时制;5位:12小时制时为0表示上午,1表示下午,24小时制时,和4位一起表示小时的十位;
其余的时间一样的表示。
倒数第二行:只看7位:为WP=1时禁止写数据,所以开始写数据时必须置0;
#include "ds1302.h"/********************************************************************/ /*单字节写入一字节数据*/ void Write_Ds1302_Byte(unsigned char dat) {unsigned char i; SCK = 0; for (i=0;i< 8;i++) { if (dat & 0x01) // 等价于if((addr & 0x01) ==1) { SDA_SET; //#define SDA_SET SDA=1 /*电平置高*/ } else { SDA_CLR; //#define SDA_CLR SDA=0 /*电平置低*/ } SCK_SET; SCK_CLR; dat = dat > > 1; } } /********************************************************************/ /*单字节读出一字节数据*/ unsigned char Read_Ds1302_Byte(void) { unsigned char i, dat=0; for (i=0;i< 8;i++) { dat = dat > > 1; if (SDA_R) //等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/ { dat |= 0x80; } else { dat &= 0x7F; } SCK_SET; SCK_CLR; } return dat; }/********************************************************************/ /*向DS1302 单字节写入一字节数据*/ void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat) { RST_CLR; /*RST脚置低,实现DS1302的初始化*/SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/RST_SET; /*启动DS1302总线,RST=1电平置高 */ addr = addr & 0xFE; Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是写操作,写之前将最低位置零*/ Write_Ds1302_Byte(dat); /*写入数据:dat*/ RST_CLR; /*停止DS1302总线*/ }/********************************************************************/ /*从DS1302单字节读出一字节数据*/ unsigned char Ds1302_Single_Byte_Read(unsigned char addr) { unsigned char temp; RST_CLR; /*RST脚置低,实现DS1302的初始化*/SCK_CLR; /*SCK脚置低,实现DS1302的初始化*/RST_SET; /*启动DS1302总线,RST=1电平置高 */ addr = addr | 0x01; Write_Ds1302_Byte(addr); /*写入目标地址:addr,保证是读操作,写之前将最低位置高*/ temp=Read_Ds1302_Byte(); /*从DS1302中读出一个字节的数据*/ RST_CLR; /*停止DS1302总线*/ return temp; }
可以自己结合官方提供的库文件,进行实时时钟显示操作。这是把官方库文件和自己所写的代码结合一起,形成一个.c文件。
#include< stc15f2k60s2.h >#defineuchar unsigned char#defineuint unsigned intsbit SCK=P1^7; sbit SDA=P2^3; sbit RST=P1^3; uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF}; uint f1,f2,f3,f4,f5,f6,f7,f8; uint ReadValue1,ReadValue2,ReadValue3,hour,minute,sec;voidWrite_Ds1302_Byte(unsignedchardat);unsignedcharRead_Ds1302_Byte(void);voidDs1302_Single_Byte_Write(unsignedcharaddr,unsignedchardat);unsignedcharDs1302_Single_Byte_Read(unsignedcharaddr);voidallinit();voiddisplay12(uchar f1,uchar f2);voiddisplay34(uchar f3,uchar f4);voiddisplay56(uchar f5,uchar f6);voiddisplay78(uchar f7,uchar f8);voiddelay();voidmain(){allinit(); f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=11;f8=11;Ds1302_Single_Byte_Write(0x8e,0x00);Ds1302_Single_Byte_Write(0x84,((18/10)< <4|(18%10)));Ds1302_Single_Byte_Write(0x82,((50/10)< <4|(50%10)));Ds1302_Single_Byte_Write(0x80,((50/10)< <4|(50%10)));Ds1302_Single_Byte_Write(0x8e,0x80);while(1){ ReadValue1=Ds1302_Single_Byte_Read(0x85); hour=((ReadValue1&0x70) > >4)*10+(ReadValue1&0x0f);Ds1302_Single_Byte_Write(0x80,0x00); ReadValue2=Ds1302_Single_Byte_Read(0x83); minute=((ReadValue2&0x70) > >4)*10+(ReadValue2&0x0f);Ds1302_Single_Byte_Write(0x80,0x00); ReadValue3=Ds1302_Single_Byte_Read(0x81); sec=((ReadValue3&0x70) > >4)*10+(ReadValue3&0x0f);Ds1302_Single_Byte_Write(0x80,0x00); f1=hour/10;f2=hour%10;f3=10; f4=minute/10;f5=minute%10;f6=10; f7=sec/10;f8=sec%10;display12(f1,f2);display34(f3,f4);display56(f5,f6);display78(f7,f8); } }voidallinit(){ P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; P2=0XC0;P0=0XFF;P2=0XFF;P0=0XFF; }/*单字节写入一字节数据*/voidWrite_Ds1302_Byte(unsignedchardat){unsignedchari; SCK =0;for(i=0;i<8;i++) {if(dat &0x01)// 等价于if((addr & 0x01) ==1){ SDA=1;//#define SDA_SET SDA=1 /*电平置高*/}else{ SDA=0;//#define SDA_CLR SDA=0 /*电平置低*/} SCK=1; SCK=0; dat = dat > >1; } }/********************************************************************//*单字节读出一字节数据*/unsignedcharRead_Ds1302_Byte(void){unsignedchari, dat=0;for(i=0;i<8;i++) { dat = dat > >1;if(SDA)//等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/{ dat |=0x80; }else{ dat &=0x7F; } SCK=1; SCK=0; }returndat; }/********************************************************************//*向DS1302 单字节写入一字节数据*/voidDs1302_Single_Byte_Write(unsignedcharaddr,unsignedchardat){ RST=0;/*RST脚置低,实现DS1302的初始化*/SCK=0;/*SCK脚置低,实现DS1302的初始化*/RST=1;/*启动DS1302总线,RST=1电平置高 */addr = addr &0xFE;Write_Ds1302_Byte(addr);/*写入目标地址:addr,保证是写操作,写之前将最低位置零*/Write_Ds1302_Byte(dat);/*写入数据:dat*/RST=0;/*停止DS1302总线*/}/********************************************************************//*从DS1302单字节读出一字节数据*/unsignedcharDs1302_Single_Byte_Read(unsignedcharaddr){unsignedchartemp; RST=0;/*RST脚置低,实现DS1302的初始化*/SCK=0;/*SCK脚置低,实现DS1302的初始化*/RST=1;/*启动DS1302总线,RST=1电平置高 */addr = addr |0x01;Write_Ds1302_Byte(addr);/*写入目标地址:addr,保证是读操作,写之前将最低位置高*/temp=Read_Ds1302_Byte();/*从DS1302中读出一个字节的数据*/RST=0;/*停止DS1302总线*/returntemp; }voiddisplay12(uchar f1,uchar f2){ P2=0XC0;P0=0X01;P2=0XFF;P0=tab[f1];delay(); P2=0XC0;P0=0X02;P2=0XFF;P0=tab[f2];delay(); }voiddisplay34(uchar f3,uchar f4){ P2=0XC0;P0=0X04;P2=0XFF;P0=tab[f3];delay(); P2=0XC0;P0=0X08;P2=0XFF;P0=tab[f4];delay(); }voiddisplay56(uchar f5,uchar f6){ P2=0XC0;P0=0X10;P2=0XFF;P0=tab[f5];delay(); P2=0XC0;P0=0X20;P2=0XFF;P0=tab[f6];delay(); }voiddisplay78(uchar f7,uchar f8){ P2=0XC0;P0=0X40;P2=0XFF;P0=tab[f7];delay(); P2=0XC0;P0=0X80;P2=0XFF;P0=tab[f8];delay(); }voiddelay(){inti,j;for(i=2;i >0;i--)for(j=600;j >0;j--); }
结果与体会:
由于官方已经给出驱动文件,把驱动文件加以修改,在结合自己的显示代码,最终可以实现实时时钟。实时时钟部分只需要知道,如何读时间、如何写入初始值、转换公式是什么。
写入初始值操作:
Ds1302_Single_Byte_Write(0x8e,0x00);Ds1302_Single_Byte_Write(0x84,((18/10)< <4|(18%10)));//时Ds1302_Single_Byte_Write(0x82,((50/10)< <4|(50%10)));//分Ds1302_Single_Byte_Write(0x80,((50/10)< <4|(50%10)));//秒Ds1302_Single_Byte_Write(0x8e,0x80);
记着转换公式为:((value/10)<<4|(value%10))
读出数据操作:
ReadValue1=Ds1302_Single_Byte_Read(0x85);hour=((ReadValue1&0x70) > >4)*10+(ReadValue1&0x0f);Ds1302_Single_Byte_Write(0x80,0x00);ReadValue2=Ds1302_Single_Byte_Read(0x83);minute=((ReadValue2&0x70) > >4)*10+(ReadValue2&0x0f);Ds1302_Single_Byte_Write(0x80,0x00);ReadValue3=Ds1302_Single_Byte_Read(0x81);sec=((ReadValue3&0x70) > >4)*10+(ReadValue3&0x0f);Ds1302_Single_Byte_Write(0x80,0x00);
记着转换公式为:((ReadValue&0x70)>>4)*10+(ReadValue&0x0f)
另外写入、读出年、星期、月、日也是如此,只要修改写入、读出初始值就OK了。
实例一是把所有定义的函数都放到一起了,接下来的实例二,是分模块化实现功能。两种方法都可以实现实时时钟,不过分模块化更有利于修改代码,所以对于以后多个功能的实现,分块处理,代码修改比较方便。
#include"ds1302.h"unsignedchartime[]={58,58,17,0,0,0,0};/********************************************************************//*单字节写入一字节数据*/voidWrite_Ds1302_Byte(unsignedchardat){unsignedchari; SCK =0;for(i=0;i<8;i++) {if(dat &0x01)// 等价于if((addr & 0x01) ==1){ SDA_SET;//#define SDA_SET SDA=1 /*电平置高*/}else{ SDA_CLR;//#define SDA_CLR SDA=0 /*电平置低*/} SCK_SET; SCK_CLR; dat = dat > >1; } }/********************************************************************//*单字节读出一字节数据*/unsignedcharRead_Ds1302_Byte(void){unsignedchari, dat=0;for(i=0;i<8;i++) { dat = dat > >1;if(SDA_R)//等价于if(SDA_R==1) #define SDA_R SDA /*电平读取*/{ dat |=0x80; }else{ dat &=0x7F; } SCK_SET; SCK_CLR; }returndat; }/********************************************************************//*向DS1302 单字节写入一字节数据*/voidDs1302_Single_Byte_Write(unsignedcharaddr,unsignedchardat){ RST_CLR;/*RST脚置低,实现DS1302的初始化*/SCK_CLR;/*SCK脚置低,实现DS1302的初始化*/RST_SET;/*启动DS1302总线,RST=1电平置高 */addr = addr &0xFE;Write_Ds1302_Byte(addr);/*写入目标地址:addr,保证是写操作,写之前将最低位置零*/Write_Ds1302_Byte((dat/10< <4)|(dat%10));/*写入数据:dat*/RST_CLR;/*停止DS1302总线*/}/********************************************************************//*从DS1302单字节读出一字节数据*/unsignedcharDs1302_Single_Byte_Read(unsignedcharaddr){unsignedchartemp;unsignedchardat1,dat2; RST_CLR;/*RST脚置低,实现DS1302的初始化*/SCK_CLR;/*SCK脚置低,实现DS1302的初始化*/RST_SET;/*启动DS1302总线,RST=1电平置高 */addr = addr |0x01;Write_Ds1302_Byte(addr);/*写入目标地址:addr,保证是读操作,写之前将最低位置高*/temp=Read_Ds1302_Byte();/*从DS1302中读出一个字节的数据*/dat1=temp/16; dat2=temp%16; temp=10*dat1+dat2;//RST_CLR; /*停止DS1302总线*/SD=0;returntemp; }voidDs1302_init(){unsignedchari,add; add=0x80;Ds1302_Single_Byte_Write(0x8e,0x00);for(i=0;i<7;i++){Ds1302_Single_Byte_Write(add,time[i]); add+=2; }Ds1302_Single_Byte_Write(0x8e,0x80); }voidDs1302_Gettime(){unsignedchari,add; add=0x81;Ds1302_Single_Byte_Write(0x8e,0x00);for(i=0;i<7;i++){ time[i]=Ds1302_Single_Byte_Read(add); add+=2; }Ds1302_Single_Byte_Write(0x8e,0x80); }
#ifndef__DS1302_H__ #define __DS1302_H__#include< stc15f2k60s2.h >#include< intrins.h >/********************************************************************/ sbit SCK=P1^7; sbit SD=P2^3; sbit RST=P1^3; /********************************************************************/ /*复位脚*/#define RST_CLR RST=0 /*电平置低*/ #define RST_SET RST=1 /*电平置高*//*双向数据*/#define SDA_CLR SD=0 /*电平置低*/ #define SDA_SET SD=1 /*电平置高*/#define SDA_R SD /*电平读取*/ /*时钟信号*/ #define SCK_CLR SCK=0 /*时钟信号*/#define SCK_SET SCK=1 /*电平置高*/ /********************************************************************/ #define ds1302_sec_addr 0x80 //秒数据地址 #define ds1302_min_addr 0x82 //分数据地址 #define ds1302_hr_addr 0x84 //时数据地址 #define ds1302_date_addr 0x86 //日数据地址 #define ds1302_month_addr 0x88 //月数据地址 #define ds1302_day_addr 0x8A //星期数据地址 #define ds1302_year_addr 0x8C //年数据地址 #define ds1302_control_addr 0x8Ee //写保护命令字单元地址 #define ds1302_charger_addr 0x90 //涓电流充电命令字地址 #define ds1302_clkburst_addr 0xBE //日历、时钟突发模式命令字地址 /********************************************************************/ /********************************************************************/ /*单字节写入一字节数据*/ extern void Write_Ds1302_Byte(unsigned char dat); /********************************************************************/ /*单字节读出一字节数据*/ extern unsigned char Read_Ds1302_Byte(void); /********************************************************************/ /********************************************************************/ /*向DS1302单字节写入一字节数据*/ extern void Ds1302_Single_Byte_Write(unsigned char addr, unsigned char dat);/********************************************************************/ /*从DS1302单字节读出一字节数据*/ extern unsigned char Ds1302_Single_Byte_Read(unsigned char addr); extern unsigned char time[]; extern void Ds1302_init(); extern void Ds1302_Gettime(); #endif /********************************************************************/ // END FILE /********************************************************************/
#include< stc15f2k60s2.h >#include"ds1302.h"#defineuchar unsigned charuchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};unsignedcharf1,f2,f3,f4,f5,f6,f7,f8;voiddelay();voidallinit();voiddisplay12(uchar f1,uchar f2);voiddisplay34(uchar f3,uchar f4);voiddisplay56(uchar f5,uchar f6);voiddisplay78(uchar f7,uchar f8);voidmain(){allinit();Ds1302_init();while(1) {Ds1302_Gettime(); f1=time[2]/10;f2=time[2]%10;f3=10; f4=time[1]/10;f5=time[1]%10;f6=10; f7=time[0]/10;f8=time[0]%10;display12(f1,f2);display34(f3,f4);display56(f5,f6);display78(f7,f8); } }voiddelay(){unsignedinti,j;for(i=0;i<2;i++)for(j=0;j<200;j++); }voidallinit(){ P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; P2=0XC0;P0=0XFF;P2=0XFF;P0=0XFF; }voiddisplay12(uchar f1,uchar f2){ P2=0XC0;P0=0X01;P2=0XFF;P0=tab[f1];delay(); P2=0XC0;P0=0X02;P2=0XFF;P0=tab[f2];delay(); }voiddisplay34(uchar f3,uchar f4){ P2=0XC0;P0=0X04;P2=0XFF;P0=tab[f3];delay(); P2=0XC0;P0=0X08;P2=0XFF;P0=tab[f4];delay(); }voiddisplay56(uchar f5,uchar f6){ P2=0XC0;P0=0X10;P2=0XFF;P0=tab[f5];delay(); P2=0XC0;P0=0X20;P2=0XFF;P0=tab[f6];delay(); }voiddisplay78(uchar f7,uchar f8){ P2=0XC0;P0=0X40;P2=0XFF;P0=tab[f7];delay(); P2=0XC0;P0=0X80;P2=0XFF;P0=tab[f8];delay(); }
结果与体会:
ds1302.c
此代码和官方给出的驱动有所修改,增加了DS1302初始化函数和获取时间的函数,还有在向DS1302单字节写入一字节数据,修改:
Write_Ds1302_Byte((dat/10<< 4)|(dat%10));
/从DS1302单字节读出一字节数据/函数修改为:
dat1=temp/16; dat2=temp%16;temp=10*dat1+dat2; //RST_CLR;/*停止DS1302总线*/SD=0;returntemp;
只要注意转换公式就可以了。
ds1302.h
要增加新定义的函数说明。
全部0条评论
快来发表一下你的评论吧 !