//基于AT89S52的万年历程序
//所用主要芯片;万年历芯片DS1302,温度传感器DS18B20
//程序撰写:我很单片机(乐乐)
//2008年4月于天津理工大学
//注1 (可以依靠按键自行调整时间)
//注2 可自行判断闰年程序(2000-2099)
//注3 如果运行发现问题会继续更改
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCDDATA P0
uchar code w[][3]={"MON","TUE","WED","TUR","FRI","SAT","SUN"};
uchar code t[]={"TEMP"};
sbit DQ=P3^2; //18B20数据
sbit RS= P3^5;
sbit RW= P3^6;
sbit E= P3^4;
sbit BUSY=P0^7;
sbit DATA=P2^7;
sbit SCLK=P2^6;
sbit RST=P3^7;
uchar x_key,y_key,keytemp;
void delay(uint t)
{uchar j;
while(t--)
{for(j=0;j<125;j++);}
}
void test_busy()
{
do{LCDDATA=0XFF;
RS=0;
RW=1;
E=0;
E=1;}
while(BUSY);
}
void write_com(com)
{
RS=0;
RW=0;
LCDDATA=com;
E=0;
_nop_();
E=1;
}
void write_data(da)
{
RS=1;
RW=0;
LCDDATA=da;
E=0;
_nop_();
E=1;
}
void delay1820(uint x)
{ uint b=0;
uchar i;
while(b++<x)
{for(i=0;i<1;i++);}
}
uchar reset_18b20() //监测18b20
{//uchar ack=1;
DQ=0;
delay1820(18); //480us以上
DQ=1;
delay1820(1); //15~60us
if(DQ)
{delay1820(5); //60~240us
return 1; }
else
{delay1820(5); //60~240us
return 0;}
}
uchar read_18b20()
{uchar j,redat=0;
for(j=8;j>0;j--)
{ redat>>=1;
DQ=0;
DQ=1;
if(DQ) redat|=0x80;
delay1820(2); //60~120us
DQ=1;
}
DQ=1; //养成习惯读完字节时序线置1
return (redat);
}
void write_18b20(uchar wrdat)
{ uchar j;
for(j=8;j>0;j--)
{DQ=0;
if(wrdat&0x01)DQ=1;
else DQ=0;
delay1820(1); //15~60us
DQ=1;
wrdat>>=1;
}
DQ=1;
}
void start_18b20()
{uchar temp_h,temp_l,zheng,reset=1;
uint temp=0;
uchar wendu_h,wendu_l;
while(reset==1){reset=reset_18b20();} //监测到18b20否?
write_18b20(0xCC); //跳过读rom指令
write_18b20(0x44); //启动温度转换启动温度转换
delay1820(40000); //延时750ms
reset=reset_18b20();
while(reset==1){reset=reset_18b20();}
write_18b20(0xcc); //跳过读rom指令
write_18b20(0xbe); //读取温度寄存器等(共可读9个寄存器) 前两个就是温度
temp_l=read_18b20();
temp_h=read_18b20();
temp=(temp|temp_h)<<8; //处理数据
temp=temp|temp_l;
if(temp_h&0x08) //如果为负数,转为原码
{temp=~(temp-1);
}
zheng=temp/16; //转化为实际温度值
if(temp_h&0x08) zheng++; //小数部分四舍五入
wendu_h= zheng/10+48;
wendu_l= zheng%10+48;
test_busy();
write_com(0x8e);
test_busy();
write_data(wendu_h);
test_busy();
write_data(wendu_l);
}
void lcd_init()
{delay(500);
delay(15);
write_com(0x38);
delay(5);
write_com(0x38);
delay(5);
write_com(0x38);
test_busy();
write_com(0x38); //设置16*2显示 5*7点阵 8为数据接口
test_busy();
write_com(0x01); //显示清屏
test_busy();
write_com(0x0c); //开显示 关光标
test_busy();
write_com(0x06); //指针加1 屏显示不移动
}
//向DS1302写一字节数据,address为命令字节
void write1302byte(uchar command,uchar writedata){
uchar j;
RST=0;
SCLK=0;
RST=1;
for(j=0;j<=7;j++){
if(command&0x01) DATA=1;
else DATA=0;
SCLK=1;
command>>=1;
SCLK=0;
}
for(j=0;j<=7;j++){
if(writedata&0x01) DATA=1;
else DATA=0;
SCLK=1;
writedata>>=1;
SCLK=0;
}
RST=0;
}
//读取DS1302一字节数据,address为命令字节
uchar read1302byte(uchar command){
uchar i,k=0;
RST=0;
SCLK=0;
RST=1;
for(i=0;i<8;i++){
if(command&0x01) DATA=1;
else DATA=0;
SCLK=1;
command>>=1;
if(i!=7) SCLK=0;
}
k=0;
for(i=0;i<8;i++){
k>>=1;
SCLK=0;
if(DATA) k|=0x80;
SCLK=1;
}
RST=0;
return(k);
}
dis_m(uchar x) //显示'pm'or'am'
{test_busy();
write_com(0xc0);
test_busy();
write_data(x);
test_busy();
write_data('M');
}
void display_min()
{ uchar min,min_h,min_l;
min=read1302byte(0x83); //1302读出数据为BCD码
min_h=min/16+48; //转成待1602液晶显示的ASCII码
min_l=min%16+48;
test_busy();
write_com(0xc5);
test_busy();
write_data(min_h);
test_busy();
write_data(min_l);
}
display_hour()
{
uchar hour,hour_h,hour_l,hourflag; //hourflag区分中午12点or凌晨12点标志位
hour=read1302byte(0x85);
hourflag=hour&0x20;
if(hourflag) dis_m('P'); //A/P=1 PM
else dis_m('A'); //A/P=0 AM
hour=hour&0x1f;
hour_h=hour/16+48;
hour_l=hour%16+48;
if((hour==0)&&(hourflag)) //中午12点显示12点,凌晨12点显示0点
{hour_h=49;hour_l=50;}
write_com(0xc2);
test_busy();
write_data(hour_h);
test_busy();
write_data(hour_l);
}
display_day()
{
uchar day,day_h,day_l;
day=read1302byte(0x87);
day_h=day/16+48;
day_l=day%16+48;
test_busy();
write_com(0x86);
test_busy();
write_data(day_h);
test_busy();
write_data(day_l);
}
display_mon()
{
uchar mon,mon_h,mon_l;
mon=read1302byte(0x89);
mon_h=mon/16+48;
mon_l=mon%16+48;
test_busy();
write_com(0x83);
test_busy();
write_data(mon_h);
test_busy();
write_data(mon_l);
}
display_week()
{ uchar j;
uchar week;
week=read1302byte(0x8b);
test_busy();
write_com(0xca);
for(j=0;j<3;j++)
{ test_busy();
write_data(w[week-1][j]);
}
}
display_year()
{
uchar year,year_h,year_l;
year=read1302byte(0x8d);
year_h=year/16+48;
year_l=year%16+48;
test_busy();
write_com(0x80);
test_busy();
write_data(year_h);
test_busy();
write_data(year_l);
}
void deal_min() //按键调整时间(调分钟)
{uchar min1;
min1=read1302byte(0x83); //读出1302数据为BCD码
min1=(min1>>4)*10+(min1&0x0f); //转为10进制数据
min1++;
if(min1==60) min1=0; //是否超出时间范围
min1=(min1/10)*16+min1%10; //转成BCD码送回1302
write1302byte(0x82,min1);
}
void deal_hour()
{uchar hour1,hour2;
hour1=read1302byte(0x85);
hour2=hour1;
hour1=hour1&0X1F;
hour1=(hour1>>4)*10+(hour1&0x0f);
hour1++;
if(hour1==12)
{hour1=0;
hour2=(~hour2)&0x20;
}
else hour2&=0x20;
hour1=(hour1/10)*16+hour1%10;
hour2=hour2|hour1;
write1302byte(0x84,hour2|0x80);
}
void doweek(x) //调整星期 没有自己的按键控制,随年月日的按键,自动变化
{uchar week2;
week2=read1302byte(0x8b);
week2+=x;
if(week2>7) week2%=7;
write1302byte(0x8a,week2);
}
void doweek_feb()
{uchar leap;
leap=read1302byte(0x8d);
leap=(leap>>4)*10+(leap&0x0f);
if(leap%4==0) doweek(1);
else doweek(0);
}
void doweek_dec()
{uchar leap;
leap=read1302byte(0x8d);
leap=(leap>>4)*10+(leap&0x0f);
if(leap%4==0) doweek(50);
else doweek(44);
}
void deal_month()
{uchar mon1;
mon1=read1302byte(0x89);
switch(mon1)
{case 1: doweek(3); break; //1月N日的星期与2月的N日差3天
case 2: doweek_feb(); break;
case 3: doweek(3); break;
case 4: doweek(2); break;
case 5: doweek(3); break;
case 6: doweek(2); break;
case 7: doweek(3); break;
case 8: doweek(3); break;
case 9: doweek(2); break;
case 0x10: doweek(3); break;
case 0x11: doweek(2); break;
case 0x12: doweek_dec(); break; //12月N日与当年的1月N日的星期差50天
default:break;
}
mon1=(mon1>>4)*10+(mon1&0x0f);
mon1++;
if(mon1>12) mon1=1;
mon1=(mon1/10)*16+mon1%10;
write1302byte(0x88,mon1);
}
void deal_year() //跨过闰年星期加2,平年星期加1
{uchar year1,month2;
year1=read1302byte(0x8d);
year1=(year1>>4)*10+(year1&0x0f);
month2=read1302byte(0x89);
if((month2<=2&&year1%4==0)||(month2>2&&year1%4==3))
doweek(2);
else doweek(1);
year1++;
if(year1>99) year1=0;
year1=(year1/10)*16+year1%10;
write1302byte(0x8c,year1);
}
void natural(uchar x) //除2月其他月份处理方法相同
{uchar day1;
day1=read1302byte(0x87);
day1=(day1>>4)*10+(day1&0x0f);
day1++;
if(day1>x) {day1=1;write1302byte(0x8a,x-29);}
day1=(day1/10)*16+day1%10;
write1302byte(0x86,day1);
}
void especial() //2月特殊,闰年2月29,平年28 (限于2000~2099年)
{uchar leap;
leap=read1302byte(0x8