基于51单片机的DS12C887电子钟万年历( proteus仿真+程序+讲解视频)
仿真图proteus 7.8及以上
程序编译器:keil 4/keil 5
编程语言:C语言
设计编号:S0028
讲解视频
基于51单片机的DS12C887万年历带农历温度显示仿真设计
主要功能:
结合实际情况,基于51单片机设计一个电子钟万年历。该系统应满足的功能要求为:
DS12C887时钟芯片,LED显示、独立键盘、农历显示、温度显示。
具体功能:
1、采用DS12C887记录日历和时间。
2、 通过数码管显示,可以显示新历年月日时分秒,农历和星期,带有温度显示。
3、可以按照实际,通过按键设置日期、时间。
以下为本设计资料展示图:
仿真图
主图
开始仿真
开始显示程序设置的初始时间,三组数码管分别显示年月日,时钟分钟秒、农历日期和温度。可以通过按键调整时间。
设置键按下第一下设置分钟,第二下设置时钟,第三下设置星期,第四下设置日期,第五下设置月份,第六下设置年份,第七下退出设置。通过按键DOWN和按键UP调整数值加减。如果已经调整好日期时间,按OUT按键可以退出设置。
程序:
ds12c887初始化和调用
#include "main.h"
#include "ds12c887.h"
void DS12C887_write(uchar add,uchar dat) //写
{
DS12C887_CS=0;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_WR=1;
DS12C887_DATA=add;
DS12C887_AS=0;
DS12C887_WR=0;
DS12C887_DATA=dat;
DS12C887_WR=1;
DS12C887_AS=1;
DS12C887_CS=1;
}
uchar DS12C887_read(uchar add) //读
{
uchar ds_date;
DS12C887_AS=1;
DS12C887_DS=1;
DS12C887_WR=1;
DS12C887_CS=0;
DS12C887_DATA=add;
DS12C887_AS=0;
DS12C887_DS=0;
DS12C887_DATA=0xff;
ds_date=DS12C887_DATA;
DS12C887_DS=1;
DS12C887_AS=1;
DS12C887_CS=1;
return ds_date;
}
void DS12C887_Gettime() //获取DS12C887时间
{
time_year =DS12C887_read(0x09); //年
time_month =DS12C887_read(0x08); //月
time_day = DS12C887_read(0x07); //日
time_week =DS12C887_read(0x06); //周
time_hour =DS12C887_read(0x04); //是
time_min = DS12C887_read(0x02); //分
time_sec = DS12C887_read(0x00); //秒
}
void DS12C887_Settime() ///设置初始时间
{
DS12C887_write(0x09,0x16); //年22 0x16->22
DS12C887_write(0x08,0x0C); //月12 0x0C->12
DS12C887_write(0x07,0x0C); //日11 0x0B->11
DS12C887_write(0x06,0x01); //周1
DS12C887_write(0x04,0x17); //时23
DS12C887_write(0x02,0x3B); //分59
DS12C887_write(0x00,0x32); //秒50
}
void DS12C887_init() //DS12C887初始化
{
DS12C887_write(0x0a,0x20); //DS12CR887寄存器A功能设置,开启时钟振荡器
DS12C887_write(0x0b,0x06); //寄存器B功能设置,不开启闹钟中断使能,数据模式为二进制,24小时模式。
}
阴历计算
/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/
/*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0*/
// /* static*/ unsigned char /*bit*/ get_moon_day(uchar month_p,uint table_addr)
// {
// uchar temp;
// switch (month_p){
// case 1:{temp=year_code[table_addr]&0x08;
// if (temp==0)return(0);else return(1);}
// case 2:{temp=year_code[table_addr]&0x04;
// if (temp==0)return(0);else return(1);}
// case 3:{temp=year_code[table_addr]&0x02;
// if (temp==0)return(0);else return(1);}
// case 4:{temp=year_code[table_addr]&0x01;
// if (temp==0)return(0);else return(1);}
// case 5:{temp=year_code[table_addr+1]&0x80;
// if (temp==0) return(0);else return(1);}
// case 6:{temp=year_code[table_addr+1]&0x40;
// if (temp==0)return(0);else return(1);}
// case 7:{temp=year_code[table_addr+1]&0x20;
// if (temp==0)return(0);else return(1);}
// case 8:{temp=year_code[table_addr+1]&0x10;
// if (temp==0)return(0);else return(1);}
// case 9:{temp=year_code[table_addr+1]&0x08;
// if (temp==0)return(0);else return(1);}
// case 10:{temp=year_code[table_addr+1]&0x04;
// if (temp==0)return(0);else return(1);}
// case 11:{temp=year_code[table_addr+1]&0x02;
// if (temp==0)return(0);else return(1);}
// case 12:{temp=year_code[table_addr+1]&0x01;
// if (temp==0)return(0);else return(1);}
// case 13:{temp=year_code[table_addr+2]&0x80;
// if (temp==0)return(0);else return(1);}
// }
// return(0);
// }
/*月份数据表-----------------------------------------------------------------------------*/
static unsigned char code day_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
static unsigned short code day_code2[3]={0x111,0x130,0x14e};
/*子函数,用于读取数据表中农历月的大月或小月,如果该月为大返回1,为小返回0------------------*/
static unsigned char get_moon_day(unsigned char month_p,unsigned short table_addr)
{
switch (month_p)
{
case 1:
if((year_code[table_addr]&0x08)==0) return(0);
else return(1);
case 2:
if((year_code[table_addr]&0x04)==0) return(0);
else return(1);
case 3:
if((year_code[table_addr]&0x02)==0) return(0);
else return(1);
case 4:
if((year_code[table_addr]&0x01)==0) return(0);
else return(1);
case 5:
if((year_code[table_addr+1]&0x80)==0) return(0);
else return(1);
case 6:
if((year_code[table_addr+1]&0x40)==0) return(0);
else return(1);
case 7:
if((year_code[table_addr+1]&0x20)==0) return(0);
else return(1);
case 8:
if((year_code[table_addr+1]&0x10)==0) return(0);
else return(1);
case 9:
if((year_code[table_addr+1]&0x08)==0) return(0);
else return(1);
case 10:
if((year_code[table_addr+1]&0x04)==0) return(0);
else return(1);
case 11:
if((year_code[table_addr+1]&0x02)==0) return(0);
else return(1);
case 12:
if((year_code[table_addr+1]&0x01)==0) return(0);
else return(1);
case 13:
if((year_code[table_addr+2]&0x80)==0) return(0);
else return(1);
}
return(0);
}
/*
函数功能:输入BCD阳历数据,输出BCD阴历数据(只允许1901-2099年)
调用函数示例:Conversion(c_sun,year_sun,month_sun,day_sun)
如:计算2004年10月16日Conversion(0,0x4,0x10,0x16);
c_sun,year_sun,month_sun,day_sun均为BCD数据,c_sun为世纪标志位,c_sun=0为21世
纪,c_sun=1为19世纪
调用函数后,原有数据不变,读c_moon,year_moon,month_moon,day_moon得出阴历BCD数据
*/
void Conversion(bit c,uchar year,uchar month,uchar day)
{ //c=0 为21世纪,c=1 为19世纪 输入输出数据均为BCD数据
// uchar c_moon,year_moon,month_moon,day_moon;
uchar temp1,temp2,temp3,month_p;
uint temp4,table_addr;
bit flag2,flag_y;
// temp1=year/16; //BCD->hex 先把数据转换为十六进制 这段要屏蔽掉,不然数码管显示乱码
// temp2=year%16;
// year=temp1*10+temp2;
// temp1=month/16;
// temp2=month%16;
// month=temp1*10+temp2;
// temp1=day/16;
// temp2=day%16;
// day=temp1*10+temp2;
//定位数据表地址
if(c==0)
{
table_addr=(year+0x64-1)*0x3;
}
else
{
table_addr=(year-1)*0x3;
}
//定位数据表地址完成
//取当年春节所在的公历月份
temp1=year_code[table_addr+2]&0x60;
temp1=_cror_(temp1,5);
//取当年春节所在的公历月份完成
//取当年春节所在的公历日
temp2=year_code[table_addr+2]&0x1f;
//取当年春节所在的公历日完成
// 计算当年春年离当年元旦的天数,春节只会在公历1月或2月
if(temp1==0x1)
{
temp3=temp2-1;
}
else
{
temp3=temp2+0x1f-1;
}
// 计算当年春年离当年元旦的天数完成
//计算公历日离当年元旦的天数,为了减少运算,用了两个表
//day_code1[9],day_code2[3]
//如果公历月在九月或前,天数会少于0xff,用表day_code1[9],
//在九月后,天数大于0xff,用表day_code2[3]
//如输入公历日为8月10日,则公历日离元旦天数为day_code1[8-1]+10-1
//如输入公历日为11月10日,则公历日离元旦天数为day_code2[11-10]+10-1
if (month<10)
{
temp4=day_code1[month-1]+day-1;
}
else
{
temp4=day_code2[month-10]+day-1;
}
if ((month>0x2)&&(year%0x4==0))
{
//如果公历月大于2月并且该年的2月为闰月,天数加1
temp4+=1;
}
//计算公历日离当年元旦的天数完成
//判断公历日在春节前还是春节后
if (temp4>=temp3){ //公历日在春节后或就是春节当日使用下面代码进行运算
temp4-=temp3;
month=0x1;
month_p=0x1; //month_p为月份指向,公历日在春节前或就是春节当日month_p指向首月
flag2=get_moon_day(month_p,table_addr);
//检查该农历月为大小还是小月,大月返回1,小月返回0
flag_y=0;
if(flag2==0)temp1=0x1d; //小月29天
else temp1=0x1e; //大小30天
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4); //从数据表中取该年的闰月月份,如为0则该年无闰月
while(temp4>=temp1){
temp4-=temp1;
month_p+=1;
if(month==temp2){
flag_y=~flag_y;
if(flag_y==0)month+=1;
}
else month+=1;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp4+1;
}
else{ //公历日在春节前使用下面代码进行运算
temp3-=temp4;
if (year==0x0){year=0x63;c=1;}
else year-=1;
table_addr-=0x3;
month=0xc;
temp2=year_code[table_addr]&0xf0;
temp2=_cror_(temp2,4);
if (temp2==0)month_p=0xc;
else month_p=0xd; //
/*
month_p为月份指向,如果当年有闰月,一年有十三个月,月指向13,
无闰月指向12
*/
flag_y=0;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
while(temp3>temp1){
temp3-=temp1;
month_p-=1;
if(flag_y==0)month-=1;
if(month==temp2)flag_y=~flag_y;
flag2=get_moon_day(month_p,table_addr);
if(flag2==0)temp1=0x1d;
else temp1=0x1e;
}
day=temp1-temp3+1;
}
// c_moon=c; //HEX->BCD ,运算结束后,把数据转换为BCD数据
// temp1=year/10;
// temp1=_crol_(temp1,4);
// temp2=year%10;
// year_moon=temp1|temp2;
// temp1=month/10;
// temp1=_crol_(temp1,4);
// temp2=month%10;
// month_moon=temp1|temp2;
// temp1=day/10;
// temp1=_crol_(temp1,4);
// temp2=day%10;
// day_moon=temp1|temp2;
c_moon=c;
year_moon=year;
month_moon=month;
day_moon=day;
}
资料清单:
下载地址见文章开头