本讲内容:
介绍DS1302实时时钟芯片基本知识,演示DS1302例程。
DS1302实时时钟:
DS1302能提供包括秒、分、时、日期、月份和年份信息。闰年可自行调整,可选择12小时制和24小时制,可以设置AM、PM。
只通过三根线进行数据的控制和传递:/RST、I/O、SCLK。
通过备用电源可以让芯片在小于1mw的功率下运作。
DS1302是总线驱动方式,它不仅要向寄存器写入控制字,还需要读取相应寄存器的数据。要想与DS1302通信,首先要先了解DS1302的控制字。DS1302的控制字如图。
位7:必须是逻辑1,如果它为0,则不能把数据写入到DS1302中。
位6:如果为0,则表示存取日历时钟数据,为1表示存取RAM数据。
位5至位1(A4~A0):指示操作单元的地址。
位0:为1表示进行读操作,为0表示要进行写操作,控制字后SCLK下降沿读数据,SCLK上升沿写数据。数据是低位在前,高位在后。
读数据:
读数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的下降沿,读出DS1302的数据,读出的数据是从最低位到最高位。
写数据:
写数据时在紧跟8位的控制字指令后的下一个SCLK脉冲的上升沿,数据被写入DS1302,数据输入也是从最低位(0位)开始。
DS1302的数据读写是通过I/O串行进行的。当进行一次读写操作时最少要读写两个字节。
第一个字节是控制字节,就是一个命令,告诉DS1302是读还是写操作,是对RAM还是对CLOCK寄存器操作,以及操作的地址。
第二个字节就是要读或写的数据了。
单字节写:
在进行操作之前先将CE(也可说是RST)置高电平,然后单片机将控制字的位0放到I/O上,当I/O的数据稳定后,将SCLK置高电平,DS1302检测到SCLK的上升沿后就将I/O上的数据读取,然后单片机将SCLK置为低电平,再将控制字的位1放到I/O上,如此反复,将一个字节控制字的8个位传给DS1302。接下来就是传一个字节的数据给DS1302,当传完数据后,单片机将CE置为低电平,操作结束。
单字节读:
一开始写控制字的过程和上面的单字节写操作是一样,但是单字节读操作在写控制字的最后一个位,SCLK还在高电平时,DS1302就将数据放到I/O上,单片机将SCLK置为低电平后数据锁存,单片机就可以读取I/O上的数据。如此反复,将一个字节的数据读入单片机。
DS1302实时时钟芯片接口电路:
例程:
/**************DS1302_LCD1602显示****************
*单片机型号:STC89C52RC
*开发环境:KEIL
*名称:DS1302_LCD1602显示
********************************************************/
#include
#define uint unsigned int
#define uchar unsigned char
uchar a,miao,shi,fen,ri,yue,nian,week,flag,temp,KEYn;
#define yh 0x80 //第一行的初始位置
#define er 0x80+0x40 //第二行初始位置
sbit wr=P1^1;sbit rs=P1^0;sbit en=P2^5;
sbit SCLK=P2^1;sbit IO=P2^0;
sbit RST=P2^4;sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
sbit key=P3^7;
sbit SWITCH_S6=P3^0;
sbit SWITCH_S11=P3^1;
sbit SWITCH_S16=P3^2;
uchar code tab1[]={"2009- - THU"};
uchar code tab2[]={" : : "};
void delay(int In,int Out)
{
int i,j;
for(i=0;i
{for(j=0;j
}
/******************液晶相关函数********************/
void write_1602com(uchar com) //液晶写入指令函数
{
rs=0; //置为写入命令
P0=com; //送入数据
delay(5,10);
en=1; //拉高使能端
delay(5,10);
en=0; //完成高脉冲
}
void write_1602dat(uchar dat)
{
rs=1; //置为写入数据
P0=dat; //送入数据
delay(5,10);
en=1;
delay(5,10);
en=0;
}
void lcd_init(void)
{
wr=0;
write_1602com(0x38); //设置液晶工作模式
write_1602com(0x0c); //开显示不显示光标
write_1602com(0x06); //整屏不移动,指针加一
write_1602com(0x01);
write_1602com(yh+2); //字符写入的位置
for(a=0;a<14;a++)
{write_1602dat(tab1[a]);}
write_1602com(er+4);
for(a=0;a<8;a++)
{write_1602dat(tab2[a]);}
}
/******************DS1302相关函数********************/
void write_byte(uchar dat)
{
ACC=dat;
RST=1;
for(a=8;a>0;a--)
{
IO=ACC0;
SCLK=0;
SCLK=1;
ACC=ACC>>1;
}
}
uchar read_byte()
{
RST=1;
for(a=8;a>0;a--)
{
ACC7=IO;
SCLK=1;
SCLK=0;
ACC=ACC>>1;
}
return (ACC);
}
void write_1302(uchar add,uchar dat)
{
RST=0;
SCLK=0;
RST=1;
write_byte(add);
write_byte(dat);
SCLK=1;
RST=0;
}
uchar read_1302(uchar add)
{
uchar temp;
RST=0;
SCLK=0;
RST=1;
write_byte(add);
temp=read_byte();
SCLK=1;
RST=0;
return(temp);
}
uchar BCD_Decimal(uchar bcd)
{
uchar Decimal;
Decimal=bcd>>4;
return(Decimal=Decimal*10+(bcd&=0x0F));
}
void ds1302_init()
{
RST=0;
SCLK=0;
write_1302(0x80,miao|0x00);
}
void write_sfm(uchar add,uchar dat)
{
uchar gw,sw;
gw=dat%10;
sw=dat/10;
write_1602com(er+add);
write_1602dat(0x30+sw);
write_1602dat(0x30+gw);
}
void write_nyr(uchar add,uchar dat)
{
uchar gw,sw;
gw=dat%10;
sw=dat/10;
write_1602com(yh+add);
write_1602dat(0x30+sw);
write_1602dat(0x30+gw);
}
void write_week(uchar week) //写星期函数
{
write_1602com(yh+0x0d);
switch(week)
{
case 1:
{
write_1602dat('M');
write_1602dat('O');
write_1602dat('N');
}break;
case 2:
{
write_1602dat('T');
write_1602dat('U');
write_1602dat('E');
}break;
case 3:
{
write_1602dat('W');
write_1602dat('E');
write_1602dat('D');
}break;
case 4:
{
write_1602dat('T');
write_1602dat('H');
write_1602dat('U');
}break;
case 5:
{
write_1602dat('F');
write_1602dat('R');
write_1602dat('I');
}break;
case 6:
{
write_1602dat('S');
write_1602dat('T');
write_1602dat('A');
}break;
case 7:
{
write_1602dat('S');
write_1602dat('U');
write_1602dat('N');
}break;
}
}
/******************按键扫描相关函数*****************/
void keyscan()
{
key=0;
if(SWITCH_S6==0) //SWITCH_S6为功能键
{
delay(5,100);
if(SWITCH_S6==0)
{
while(!SWITCH_S6);
KEYn++;
if(KEYn==9)
KEYn=1;
switch(KEYn)
{
case 1:
{
TR0=0; //关闭定时器
write_1602com(er+0x0b); //写入光标位置
write_1602com(0x0f); //设置光标为闪烁
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x80|temp); //miao
write_1302(0x8e,0x80);
}break;
case 2:{write_1602com(er+8);}break; //fen
case 3:{write_1602com(er+5);}break; //shi
case 4:{write_1602com(yh+0x0f);}break; //week
case 5:{write_1602com(yh+0x0b);}break; //ri
case 6:{write_1602com(yh+0x08);}break; //yue
case 7:{write_1602com(yh+0x05);}break; //nian
case 8:
{
write_1602com(0x0c); //设置光标不闪烁
TR0=1; //打开定时器
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x00|temp); //miao
write_1302(0x8e,0x80);
}break;
}
}
}
if(KEYn!=0)
//当SWITCH_S6按下以下。再按以下键才有效
{
if(SWITCH_S11==0) //上调键
{
delay(5,10);
if(SWITCH_S11==0)
{
while(!SWITCH_S11);
switch(KEYn)
{
case 1:
{
miao++;
if(miao==60){miao=0;}
write_sfm(0x0a,miao); //写入新的秒数
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x80|temp);
write_1302(0x8e,0x80);
write_1602com(er+0x0b);
//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
}break;
case 2:
{
fen++;
if(fen==60){fen=0;}
write_sfm(0x07,fen);
temp=(fen)/10*16+(fen)%10;
write_1302(0x8e,0x00);
write_1302(0x82,temp);
write_1302(0x8e,0x80);
write_1602com(er+8);
}break;
case 3:
{
shi++;
if(shi==24){shi=0;}
write_sfm(4,shi);
temp=(shi)/10*16+(shi)%10;
write_1302(0x8e,0x00);
write_1302(0x84,temp);
write_1302(0x8e,0x80);
write_1602com(er+5);
}break;
case 4:
{
week++;
if(week==8){week=0;}
write_week(week);
write_1602com(yh+0x0f);
}break;
case 5:
{
ri++;
if(ri==31){ri=0;}
write_nyr(10,ri);
temp=(ri)/10*16+(ri)%10;
write_1302(0x8e,0x00);
write_1302(0x86,temp);
write_1302(0x8e,0x80);
write_1602com(yh+11);
}break;
case 6:
{
yue++;
if(yue==13){yue=0;}
write_nyr(7,yue);
temp=(yue)/10*16+(yue)%10;
write_1302(0x8e,0x00);
write_1302(0x88,temp);
write_1302(0x8e,0x80);
write_1602com(yh+8);
}break;
case 7:
{
nian++;
if(nian==100){nian=0;}
write_nyr(4,nian);
write_1602com(yh+5);
}break;
}
}
}
if(SWITCH_S16==0)
{
delay(5,100);
if(SWITCH_S16==0)
{
while(!SWITCH_S16);
switch(KEYn)
{
case 1:
{
miao--;
if(miao==-1){miao=59;}
write_sfm(0x0a,miao); //写入新的秒数
write_1602com(er+0x0b);
//因为设置液晶的模式是写入数据后,指针自动加一,在这里是写回原来的位置
}break;
case 2:
{
fen--;
if(fen==-1){fen=59;}
write_sfm(7,fen);
temp=(fen)/10*16+(fen)%10;
write_1302(0x8e,0x00);
write_1302(0x82,temp);
write_1302(0x8e,0x80);
write_1602com(er+8);
}break;
case 3:
{
shi--;
if(shi==-1){shi=23;}
write_sfm(4,shi);
temp=(shi)/10*16+(shi)%10;
write_1302(0x8e,0x00);
write_1302(0x84,temp);
write_1302(0x8e,0x80);
write_1602com(er+5);
}break;
case 4:
{
week--;
if(week==-1){week=7;}
write_week(week);
write_1602com(yh+0x0f);
}break;
case 5:
{
ri--;
if(ri==-1){ri=30;}
write_nyr(10,ri);
temp=(ri)/10*16+(ri)%10;
write_1302(0x8e,0x00);
write_1302(0x86,temp);
write_1302(0x8e,0x80);
write_1602com(yh+11);
}break;
case 6:
{
yue--;
if(yue==-1){yue=12;}
write_nyr(7,yue);
temp=(yue)/10*16+(yue)%10;
write_1302(0x8e,0x00);
write_1302(0x88,temp);
write_1302(0x8e,0x80);
write_1602com(yh+8);
}break;
case 7:
{
nian--;
if(nian==-1){nian=99;}
write_nyr(4,nian);
write_1602com(yh+5);
}break;
}
}
}
}
}
void timer_init(){TMOD=0x11;TH0=0;TL0=0;EA=1;ET0=1;TR0=1;}
void sys_init(void)
{
lcd_init();
ds1302_init();
timer_init();
}
void main()
{
sys_init();
while(1){keyscan();}
}
void timer0() interrupt 1
{
miao = BCD_Decimal(read_1302(0x81));
fen = BCD_Decimal(read_1302(0x83));
shi = BCD_Decimal(read_1302(0x85));
ri = BCD_Decimal(read_1302(0x87));
yue = BCD_Decimal(read_1302(0x89));
nian = BCD_Decimal(read_1302(0x8d));
week = BCD_Decimal(read_1302(0x8b));
write_sfm(10,miao);
write_sfm(7,fen);
write_sfm(4,shi);
write_nyr(10,ri);
write_nyr(7,yue);
}
最后,求求看到的此文的小伙伴点赞和关注支持一下下哦。毕竟,码字不容易哦,您的支持是我最大的动力呀!!!呜呜呜~~~