求由液晶显示模块:QC12864B、单片机:AT89C52、时钟芯片:DS1302、温度传感器:DS18B20 组成的万年历设计

各位有经验的前辈些们,本人一学生,老师要求做一万年历的课程设计,用我们学过的C语言编写程序,具体要求是可以显示时间(年月日周),可以通过按钮设置时间,使用的液晶显示模块型号为QC12864B,单片机型号为AT89C52,实时时钟芯片为DS1302,温度传感器为DS18B20.跪求各位亲们解答,有proteus仿真图最好,有Keil编写的程序编译无误的最好谢了。顺便麻烦在程序每一句后注释一下是什么意思,本人是一位单片机编程菜鸟,害怕老师问我的时候不知所以然,可以发到我的邮箱:1107981714@qq.com本人再次万分感谢!!
再次跪求前辈些们发程序给我,想想程序是很多,如果再注释的话就,确实的工作量很大,那就不用注释嘛,但是程序一定要对才行啊

第1个回答  2012-03-25
我倒是做过这个题目 不过在学校的电脑里 我那个是用12864显示的 现在估计不能帮你发来 学校里电脑没网 我现在在网吧
第2个回答  2012-03-29
这个我也做过,不过现在不方便发给你,公司不可以发邮件
第3个回答  2012-03-24
这个程序大概超过一千行每行注释10个字平均那就是1万来字啊天啊
第4个回答  2012-03-26
给你一个昨天晚上做的《可调式电子时钟》,仿真图见图片
程序源代码:
//-------------------------------------------------------------------------------------
//名称:用DS1302与1602设计的可调式电子日历时钟
//-------------------------------------------------------------------------------------
#include<reg52.h>
#include<string.h>
#define uchar unsigned char
#define uint unsigned int

sbit SDA=P1^0;//DS1302数据线
sbit CLK=P1^1;//DS1302时钟线
sbit RST=P1^2;//DS1302复位线
sbit RS=P2^0;//LCD寄存器选择
sbit RW=P2^1;//LCD读/写控制
sbit EN=P2^2;//LCD使能段
sbit K1=P3^4;//选择
sbit K2=P3^5;//加
sbit K3=P3^6;//减
sbit K4=P3^7;//确定

uchar tCount=0;
//一年中每个月的天数,2月的天数有年份决定
uchar MonthsDays[]={0,31,0,31,30,31,30,31,31,30,31,30,31};
//周日,周一到周六(0,1~6)【读取DS1302时分别是1~7】
uchar *WEEK[]={"SUN","MON","TUS","WEN","THU","FRI","SAT"};

//LCD显示缓冲
uchar LCD_DSY_BUFFER1[]={"DATE 00-00-00 "};
uchar LCD_DSY_BUFFER2[]={"TIME 00:00:00 "};

uchar DateTime[7];//所读取的日期时间
char Adjust_Index=-1;//当前调节的时间对象:秒,分,时,日,月,年(0,1,2,3,4,6)
uchar Change_Flag[]="-MHDM-Y";//(分,时,日,月,年)(不调秒与周)

void DelayMS(uint x)
{
uchar i;
while(x--) for(i=0;i<120;i++);
}

//向DS1302写入一个字节
void Write_A_Byte_TO_DS1302(uchar x)
{
uchar i;
for(i=0;i<8;i++)
{
SDA=x&1;
CLK=1;
CLK=0;
x>>=1;
}
}

//从DS1302里读取一个字节
uchar Get_A_Byte_FROM_DS1302()
{
uchar i,b,t;
for(i=0;i<8;i++)
{
b>>=1;
t=SDA;
b|=t<<7;
CLK=1;
CLK=0;
}
//BCD码转换
return b/16*10+b%16;
}

//从DS1302指定的位置读数据
uchar Read_Data(uchar addr)
{
uchar dat;
RST=0;
CLK=0;
RST=1;
Write_A_Byte_TO_DS1302(addr);
dat=Get_A_Byte_FROM_DS1302();
CLK=1;
RST=0;
return dat;
}

//向DS1302某地址写入数据
void Write_DS1302(uchar addr, uchar dat)
{
CLK=0;
RST=1;
Write_A_Byte_TO_DS1302(addr);
Write_A_Byte_TO_DS1302(dat);
CLK=0;
RST=0;
}

//设置时间
void SET_DS1302()
{
uchar i;
//写控制字,取消写保护;
Write_DS1302(0x8e,0x00);
//分时日月年依次写入
for(i=1;i<7;i++)
{
//分的起始地址100000010(0x80),后面依次是时,日,月,周,年,写入地址每次递增2
Write_DS1302(0x80+2*i,(DateTime[i]/10<<4)|(DateTime[i]&10));
}
Write_DS1302(0x8e,0x80);//加保护
}

//读取当前日期时间
void GetTime()
{
uchar i;
for(i=0;i<7;i++)
DateTime[i]=Read_Data(0x81+2*i);
}

//读LCD状态
uchar Read_LCD_State()
{
uchar state;
RS=0;
RW=1;
EN=1;
DelayMS(1);
state=P0;
EN=0;
DelayMS(1);
return state;
}

//忙等待
void LCD_Busy_Wait()
{
while((Read_LCD_State()&0x80)==0x80);
DelayMS(5);
}

//向LCD写数据
void Write_LCD_Date(uchar dat)
{
LCD_Busy_Wait();
RS=1;
RW=0;
EN=0;
P0=dat;
EN=1;
DelayMS(1);
EN=0;
}

//写指令
void Write_LCD_Command(uchar cmd)
{
LCD_Busy_Wait();
RS=0;
RW=0;
EN=0;
P0=cmd;
EN=1;
DelayMS(1);
EN=0;
}

//LCD初始化
void Init_LCD()
{
Write_LCD_Command(0X38);
DelayMS(1);
Write_LCD_Command(0x01);
DelayMS(1);
Write_LCD_Command(0x06);
DelayMS(1);
Write_LCD_Command(0x0c);
}

//设置液晶屏位置
void Set_LCD_POS(uchar p)
{
Write_LCD_Command(p|0x80);
}

//在LCD上显示字符串
void Display_LCD_String(uchar p,uchar *s)
{
uchar i;
Set_LCD_POS(p);
for(i=0;i<16;i++)
Write_LCD_Date(s[i]);
DelayMS(1);
}

//日期与时间值转换为数字符
void Format_DateTime(uchar d, uchar *a)
{
a[0]=d/10+'0';
a[1]=d%10+'0';
}

//判断是否为润年
uchar isLeapYear(uint y)
{
return(y%4==0&&y%100!=0)||(y%400==0);
}

//求自2000.1.1开始的任何一天是星期几
//函数没有通过,求出总天数后再求星期几
//因为求总天数可能会越出uint的范围
void RefreshWeekDay()
{
uint i, d, w=5;//已知1999.12.31是周五
for(i=2000;i<2000+DateTime[6];i++)
{
d=isLeapYear(i) ? 366:365;
w=(w+d)%7;
}
d=0;
for(i=1;i<DateTime[4];i++)
d+=MonthsDays[i];
d+=DateTime[3];
//保存星期,0~6表示星期日,星期一,二,...六,为了与DS1302的星期格式匹配,返回值需要加1
DateTime[5]=(w+d)%7+1;
}

//年月日时分++/--
void DateTime_Adjust(char x)
{
switch(Adjust_Index)
{
case 6://年00~99
if(x==1&&DateTime[6]<99) DateTime[6]++;
if(x==-1&&DateTime[6]>0) DateTime[6]--;
//获取2月天数
MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
//如果年份变换后当前月份的天数大于上限则设为上限
if(DateTime[3]>MonthsDays[DateTime[4]])
DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();//刷新星期
break;
case 4://月01-12
if(x==1&&DateTime[4]<12) DateTime[4]++;
if(x==-1&&DateTime[4]>1) DateTime[4]--;
//获取2月天数
MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
//如果月份变换后当前月份的天数大于上限则设为上限
if(DateTime[3]>MonthsDays[DateTime[4]])
DateTime[3]=MonthsDays[DateTime[4]];
RefreshWeekDay();//刷新星期
break;
case 3://日00-28/29/30/31;调节之前首先根据年份得出该年中2月的天数
MonthsDays[2]=isLeapYear(2000+DateTime[6])? 29:28;
//根据当前月份决定调节日期的上限
if(x==1&&DateTime[3]<MonthsDays[DateTime[4]])

if(x==-1&&DateTime[3]>0)
DateTime[3]--;
RefreshWeekDay();//刷新星期
break;
case 2://时
if(x==1&&DateTime[2]<23)
DateTime[2]++;
if(x==-1&&DateTime[2]>0)
DateTime[2]--;
break;
case 1://分
if(x==1&&DateTime[1]<59)
DateTime[1]++;
if(x==-1&&DateTime[1]>0)
DateTime[1]--;
break;
}
}

//定时器0每秒刷新LCD显示
void T0_INT() interrupt 1
{
TH0=-50000/256;
TL0=-50000%256;
if(++tCount!=2) return;
tCount=0;
//按指定格式生成待显示的时期时间串
Format_DateTime(DateTime[6],LCD_DSY_BUFFER1+5);
Format_DateTime(DateTime[4],LCD_DSY_BUFFER1+8);
Format_DateTime(DateTime[3],LCD_DSY_BUFFER1+11);
//星期
strcpy(LCD_DSY_BUFFER1+13,WEEK[DateTime[5]-1]);
//时分秒
Format_DateTime(DateTime[2],LCD_DSY_BUFFER2+5);
Format_DateTime(DateTime[1],LCD_DSY_BUFFER2+8);
Format_DateTime(DateTime[0],LCD_DSY_BUFFER2+11);
//显示年月日,星期,时分秒
Display_LCD_String(0x00,LCD_DSY_BUFFER1);
Display_LCD_String(0x40,LCD_DSY_BUFFER2);
}

//键盘中断
void EX_INT0() interrupt 0
{
if(K1==0)//选择调整对象(Y M D H M)
{
while(K1==0);
if(Adjust_Index==-1||Adjust_Index==1)
Adjust_Index=7;
Adjust_Index--;
if(Adjust_Index==5)
Adjust_Index=4;//跳过对星期的调节
LCD_DSY_BUFFER2[13]='[';
LCD_DSY_BUFFER2[14]=Change_Flag[Adjust_Index];
LCD_DSY_BUFFER2[15]=']';
}
else
if(K2==0)//加
{
while(K2==0);
DateTime_Adjust(1);
}
else
if(K3==0)//减
{
while(K3==0);
DateTime_Adjust(-1);
}
else
if(K4==0)//确定
{
while(K4==0);
SET_DS1302();//将调整后的时间写入DS1302
LCD_DSY_BUFFER2[13]=' ';
LCD_DSY_BUFFER2[14]=' ';
LCD_DSY_BUFFER2[15]=' ';
Adjust_Index=-1;//操作索引重设为-1,时间继续正常显示
}
}

void main()
{
Init_LCD();//初始化液晶
IE=0x83;//允许INT0,T0中断
IP=0x01;
TMOD=0x01;
TH0=-50000/256;
TL0=-50000%256;
TR0=1;
while(1)
{
//如果未执行调整操作则正常读取当前时间
if(Adjust_Index==-1)
GetTime();
}
}
相似回答