采用外部时钟芯片DS1302,设计一个具有秒、分、日、月、年的数字时钟,采用四位一体数码管显示相关信息,秒、分显示一页,日、月显示一页,年显示一页。QQ 1282031855
下面的程序配合这个电路运行就是对的
这个是完整的程序,电路图如下
#include <reg52.h>
//定义共阳极字型码0123456789-
unsigned char code dispcode[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char time[]={0,0,0,0};//用来储存分秒
unsigned char date[]={0,0,0,0};//用来储存日时
unsigned char year[]={0,0,0,0};//用来储存年月
typedef struct __SYSTEMTIME__
{
unsigned char Second;
unsigned char Minute;
unsigned char Hour;
unsigned char Week;
unsigned char Day;
unsigned char Month;
unsigned char Year;
unsigned char DateString[9];
unsigned char TimeString[9];
}SYSTEMTIME; //定义的时间类型
SYSTEMTIME time1;
sbit DS1302_CLK = P1^6; //实时时钟时钟线引脚
sbit DS1302_IO = P1^7; //实时时钟数据线引脚
sbit DS1302_RST = P1^5; //实时时钟复位线引脚
sbit ACC0 = ACC^0;
sbit ACC7 = ACC^7;
sbit P10=P1^0;
sbit P11=P1^1;
sbit P12=P1^2;
sbit P13=P1^3;
sbit P14=P1^4;
//#define AM(X) X
//#define PM(X) (X+12) // 转成24小时制
#define DS1302_SECOND 0x80 //秒寄存器
#define DS1302_MINUTE 0x82 //分寄存器
#define DS1302_HOUR 0x84
#define DS1302_WEEK 0x8A
#define DS1302_DAY 0x86
#define DS1302_MONTH 0x88
#define DS1302_YEAR 0x8C
#define DS1302_RAM(X) (0xC0+(X)*2) //用于计算 DS1302_RAM 地址的宏
void DS1302InputByte(unsigned char d) //实时时钟写入一字节(内部函数)
{
unsigned char i;
ACC = d;
for(i=8; i>0; i--)
{
DS1302_IO = ACC0; //相当于汇编中的 RRC
DS1302_CLK = 1;
DS1302_CLK = 0; //发一个高跳变到低的脉冲
ACC = ACC >> 1;
}
}
unsigned char DS1302OutputByte(void) //实时时钟读取一字节(内部函数)
{
unsigned char i;
for(i=8; i>0; i--)
{
ACC = ACC >>1; //相当于汇编中的 RRC
ACC7 = DS1302_IO;
DS1302_CLK = 1;
DS1302_CLK = 0; //发一个高跳变到低的脉冲
}
return(ACC);
}
void Write1302(unsigned char ucAddr, unsigned char ucDa) //ucAddr: DS1302地址, ucData: 要写的数据
{
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1;
DS1302InputByte(ucAddr); // 地址,命令
DS1302InputByte(ucDa); // 写1Byte数据
DS1302_CLK = 1;
DS1302_RST = 0; //RST 0->1->0,CLK 0->1
}
unsigned char Read1302(unsigned char ucAddr) //读取DS1302某地址的数据
{
unsigned char ucData;
DS1302_RST = 0;
DS1302_CLK = 0;
DS1302_RST = 1; //enable
DS1302InputByte(ucAddr|0x01); // 地址,命令
ucData = DS1302OutputByte(); // 读1Byte数据
DS1302_CLK = 1; //RST 0->1->0,CLK 0->1
DS1302_RST = 0;
return(ucData);
}
void DS1302_SetProtect(bit flag) //是否写保护
{
if(flag)
Write1302(0x8E,0x10); //WP=1,不能写入
else
Write1302(0x8E,0x00);//WP=0,可以写入
}
void DS1302_SetTime(unsigned char Address, unsigned char Value) // 设置时间函数
{
DS1302_SetProtect(0);
Write1302(Address, ((Value/10)<<4 | (Value%10))); //高4位为十位,低4位为个位
}
void DS1302_GetTime(SYSTEMTIME *Time)
{
unsigned char ReadValue;
ReadValue = Read1302(DS1302_SECOND);
Time->Second = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//转换成10进制的秒
ReadValue = Read1302(DS1302_MINUTE);
Time->Minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_HOUR);
Time->Hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_DAY);
Time->Day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_WEEK);
Time->Week = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_MONTH);
Time->Month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
ReadValue = Read1302(DS1302_YEAR);
Time->Year = ((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F);
}
void Initial_DS1302(void)
{
unsigned char Second=Read1302(DS1302_SECOND);
if(Second&0x80) //如果第七为1(表明没有启动), 则启动时钟
DS1302_SetTime(DS1302_SECOND,0);
}
void delay(unsigned char i) //延时子程序
{
unsigned char j;
while((i--)!=0)
{
for(j=625;j>0;j--);
}
}
/*unsigned char button_time(n,x,y) //时钟调整子程序
unsigned char n,x,y;
{
if(P1^7==0)
{
delay(50);
if(P1^7==0)
{
n++;
if(n==x)
n=0;
while(P1^7==0);
}
}
if(P1^1==0)
{
delay(50);
if(P1^1==0)
{
if(n==0)
n=y;
else
n--;
while(P1^1==0);
}
}
return n;
}
*/
/*unsigned char button_date(n,x,y) //日期调整子程序
unsigned char n,x,y;
{
if(P1^7==0)
{
delay(50);
if(P1^7==0)
{
n++;
if(n==x)
n=1;
while(P1^7==0);
}
}
if(P1^1==0)
{
delay(50);
if(P1^1==0)
{
if(n==1)
n=y;
else
n--;
while(P1^1==0);
}
}
return n;
}*/
void display1(minute10,minute1,second10,second1) //显示第一页 分秒 子程序
//unsigned char second10,second1,minute10,minute1;
{
P2=0x08;
P0=dispcode[second1];//显示秒的个位
delay(1);
P2=0x04;
P0=dispcode[second10]; //显示秒的十位
delay(1);
P2=0x02;
P0=dispcode[minute1]; //显示分的个位
delay(1);
P2=0x01;
P0=dispcode[minute10];//显示分的十位
delay(1);
}
void display2(data10,data1,hour10,hour1) //显示第二页 天时 子程序
//unsigned char data10,data1,hour10,hour1;
{
P2=0xf8;
P0=dispcode[data1];//显示天的个位
delay(1);
P2=0xf4;
P0=dispcode[data10]; //显示天的十位
delay(1);
P2=0xf2;
P0=dispcode[hour1]; //显示时的个位
delay(1);
P2=0xf1;
P0=dispcode[hour10];//显示时的十位
delay(1);
}
void display3(year10,year1,month10,month1) //显示第三页 年月 子程序
//unsigned char year10,year1,month10,month1;
{
P2=0xf2;
P0=dispcode[month1];//显示月的个位
delay(1);
P2=0xf1;
P0=dispcode[month10]; //显示月的十位
delay(1);
P2=0xf8;
P0=dispcode[year1]; //显示月的个位
delay(1);
P2=0xf4;
P0=dispcode[year10];//显示月的十位
delay(1);
}
void main()
{
unsigned char flag=0;
Initial_DS1302(); //初始化DS1302这个时钟芯片,
P10=0; //点亮测试灯
while(1)
{
DS1302_GetTime(&time1); //读取时间参数
time[3]=(time1.Second)%10; //把秒的个位数据存入time[3]
time[2]=(time1.Second)/10; //把秒的十位数据存入time[2]
time[1]=(time1.Minute)%10; //把分的个位数据存入time[1]
time[0]=(time1.Minute)/10; //把分的十位数据存入time[0]
date[3]=(time1.Day)%10;
date[2]=(time1.Day)/10;
date[1]=(time1.Hour)%10;
date[0]=(time1.Hour)/10;
year[3]=(time1.Year)%10;
year[2]=(time1.Year)/10;
year[1]=(time1.Month)%10;
year[0]=(time1.Month)/10;
// display1(time[0],time[1],time[2],time[3]);
if(P11==0)
{
delay(50);
if(P11==0)
{
flag++;
if(flag>2)//flag: 1 显示第二页 日 时;2 显示第三页 年 月 0:显示第一页 分秒
{
flag=0;
}
}
while(P11==0);
}
/*if(P1^6==0) //如果按下Time Set键一下,开始显示日期,再按一下进入日期跟时钟的调节模式
{
delay(50);
if(P1^6==0)
{
flag++;
if(flag>6)
{
flag=0;
}
}
while(P1^6==0);
}*/
switch(flag)
{
case 0:display1(time[0],time[1],time[2],time[3]); //调用子函数display,把存入数组time的数据给显示出来
break;
case 1:display2(date[0],date[1],date[2],date[3]); //调用子函数display,把存入数组date的数据给显示出来
break;
case 2:display3(year[0],year[1],year[2],year[3]);
break;
/* case 3:time1.Month=button_date(time1.Month,13,12); //调整月
DS1302_SetTime(0x88,time1.Month);
display(10,10,date[2],date[3]);
break;
case 4:time1.Day=button_date(time1.Day,32,31); //调整日
DS1302_SetTime(0x86,time1.Day);
display(10,10,date[4],date[5]);
break;
case 5:time1.Minute=button_time(time1.Minute,60,59); //调整分
DS1302_SetTime(0x82,time1.Minute);
display(time[2],time[3],10,10);
break;
case 6:time1.Second=button_time(time1.Second,60,59); //调整秒
DS1302_SetTime(0x80,time1.Second);
display(10,10,time[4],time[5]);
break;*/
}
}
}