标题:
多功能单片机电子万年历程序
[打印本页]
作者:
五叶尊者
时间:
2019-2-19 13:37
标题:
多功能单片机电子万年历程序
功能:阳历+阴历+星期+闹钟+多点温度无线传输+红外+掉电走时
0.png
(10.03 KB, 下载次数: 18)
下载附件
2019-2-21 03:30 上传
单片机源程序如下:
#include <reg52.h>
#include "12864B.h"
#include "ds1302.h"
#include "DS18B20.h"
#include"NRF2401.h"
#include "delay.h"
#include "clock.h"
#include "ziku.h"
#include "gongli.h"
extern uchar week_value[2];
extern char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year; //秒,分,时到日,月,年位闪的计数
extern unsigned char hi_sec,hi_min,hi_hour,hi_day,hi_month;
extern unsigned char clock_shi,clock_fen,clock_miao,clock_month,clock_day; //闹钟秒,分,时到日,月,年位闪的计数
extern bit flag2;
extern CLOCKTIME clock_time;
unsigned char count,count1,temp,flag,up_flag,down_flag,shi,fen,miao,week,day,month,year;
unsigned char IrValue[6];
unsigned char Time;
bit done,flag1,flag2;
SYSTEMTIME CurrentTime;
sbit clock_Set=P2^3;
sbit Set = P2^4; //功能按键
sbit Up = P2^2; //加法按钮
sbit Down = P2^0; //减法按钮
sbit Out = P2^1; //立刻跳出调整模式按钮
sbit Beep = P1^5; //蜂鸣器
sbit IRIN = P3^2; //红外
void Setkey();
void timer0_1()
{
TMOD=0x01; //设置定时器0为工作方式1
TH0 = (65536 - 45872)/256; //装初值
TL0 = (65536 - 45872)%256;
EA=1; //开总中断
ET0=1; //开定时器0中断
TR0=1; //启动定时器0
}
void show_time() //液晶显示程序
{
DS1302_GetTime(&CurrentTime); //获取时钟芯片的时间数据
TimeToStr(&CurrentTime); //时间数据转换液晶字符
DateToStr(&CurrentTime); //日期数据转换液晶字符
LCD12864_SetWindow(2,0); //设置显示坐标
Print(CurrentTime.TimeString); //显示时间
LCD12864_SetWindow(0,1);
Print(CurrentTime.DateString); //显示日期
LCD12864_SetWindow(2,7);
change(); //显示星期几
lcm_w_nl(); //农历显示
Delay10ms(5); //扫描延时
}
void outkey() //跳出调整模式,返回默认显示
{
uchar Second;
if(Out==0)
{
mdelay(8);
if(Out==0)
{
if(flag1==0)
{
count=0;
flag1=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
Second=Read1302(DS1302_SECOND);
Write1302(0x8e,0x00); //写入允许
Write1302(0x80,Second&0x7f); //启动计时
Write1302(0x8E,0x80); //禁止写入
done=0;
}
else
{
count1=0;flag2=0;flag1=0;done=0;
hi_sec=0,hi_min=0,hi_hour=0,hi_day=0,hi_month=0;
LCD12864_WriteCmd(0x30);
LCD12864_WriteCmd(0x01); //清屏命令
LCD12864_WriteCmd(0x34); //扩展模式命令,关显示
gui_line(72,32,72,48); //内部线框
gui_line(0,15,127,15);
gui_line(0,32,127,32);
gui_line(0,48,127,48);
gui_line(62,48,62,63);
gui_line(0,0,127,0); //四周线框
gui_line(0,1,0,63);
gui_line(0,63,127,63);
gui_line(127,0,127,63);
GUI_Put_Area(81,33,&uMod[0][0],16,14,0); //固定显示“星”
GUI_Put_Area(96,33,&uMod[1][0],16,14,0); //固定显示“期”
GUI_Put_Area(3,18,&uMod[2][0],16,12,0); //固定显示“农”
GUI_Put_Area(19,18,&uMod[3][0],16,12,0); //固定显示“历”
LCD12864_WriteCmd(0x36); //开显示
LCD12864_WriteCmd(0x30); //基本模式命令
}
}
while(Out==0);
}
}
void Upkey() //升序按键
{
if(Up==0)
{
mdelay(8);
if(Up==0)
{
if(flag1==0)
{
switch(count)
{
case 1:
DS1302_change(0x81,&miao); //读取DS1302秒地址的数据给miao
miao=miao+1;
if(miao>=60)
miao=0;
down_flag=1;
break;
case 2:
DS1302_change(0x83,&fen); //读取DS1302分地址的数据给fen
fen=fen+1;
if(fen>=60)
fen=0;
down_flag=1;
break;
case 3:
DS1302_change(0x85,&shi);
shi=shi+1;
if(shi>=24)
shi=0;
down_flag=1;
break;
case 4:
DS1302_change(0x87,&day);
DS1302_change(0x89,&month);
day=day+1;
if(day==31&&((month==4)||(month==6)||(month==9)||(month==11)))
day=1;
if(day==30&&(month==2))
day=1;
if(day==32&&((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12)))
day=1;
down_flag=1;
break;
case 5:
DS1302_change(0x89,&month);
month=month+1;
if(month==13)
month=1;
down_flag=1;
break;
case 6:
DS1302_change(0x8d,&year);
year=year+1;
if(year==100)
year=0;
down_flag=1;
break;
default: break;
}
}
else
{
switch(count1)
{
case 1:
clock_miao=clock_miao+1; //闹钟的秒加1
if(clock_miao>=60)
clock_miao=0;
break;
case 2:
clock_fen=clock_fen+1;
if(clock_fen>=60)
clock_fen=0;
break;
case 3:
clock_shi=clock_shi+1;
if(clock_shi>=24)
clock_shi=0;
break;
case 4:
clock_day=clock_day+1;
if(clock_day==31&&((clock_month==4)||(clock_month==6)||(clock_month==9)||(clock_month==11)))
clock_day=1;
if(clock_day==30&&(clock_month==2))
clock_day=1;
if(clock_day==32&&((clock_month==1)||(clock_month==3)||(clock_month==5)||(clock_month==7)||(clock_month==8)||(clock_month==10)||(clock_month==12)))
clock_day=1;
break;
case 5:
clock_month=clock_month+1;
if(clock_month==13)
clock_month=1;
break;
default: break;
}
}
}
while(Up==0);
}
}
void Downkey() //降序按键
{
if(Down==0)
{
mdelay(8);
if(Down==0)
{
if(flag1==0)
{
switch(count)
{
case 1:
DS1302_change(0x81,&miao);
miao=miao-1;
if(miao==-1)
miao=59;
down_flag=1;
break;
case 2:
DS1302_change(0x83,&fen);
fen=fen-1;
if(fen==-1)
fen=59;
down_flag=1;
break;
case 3:
DS1302_change(0x85,&shi);
shi=shi-1;
if(shi==-1)
shi=23;
down_flag=1;
break;
case 4:
DS1302_change(0x87,&day);
DS1302_change(0x89,&month);
day=day-1;
if(day==0&&((month==4)||(month==6)||(month==9)||(month==11)))
day=30;
if(day==0&&(month==2))
day=29;
if(day==0&&((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12)))
day=31;
down_flag=1;
break;
case 5:
DS1302_change(0x89,&month);
month=month-1;
if(month==0)
month=12;
down_flag=1;
break;
case 6:
DS1302_change(0x8d,&year);
year=year-1;
if(year==-1)
year=99;
down_flag=1;
break;
default: break;
}
}
else
{
switch(count1)
{
case 1:
clock_miao=clock_miao-1; //闹钟秒减1
if(clock_miao==-1)
clock_miao=59;
break;
case 2:
clock_fen=clock_fen-1;
if(clock_fen==-1)
clock_fen=59;
break;
case 3:
clock_shi=clock_shi-1;
if(clock_shi==-1)
clock_shi=23;
break;
case 4:
clock_day=clock_day-1;
if(clock_day==0&&((clock_month==4)||(clock_month==6)||(clock_month==9)||(clock_month==11)))
clock_day=30;
if(clock_day==0&&(clock_month==2))
clock_day=29;
if(clock_day==0&&((clock_month==1)||(clock_month==3)||(clock_month==5)||(clock_month==7)||(clock_month==8)||(clock_month==10)||(clock_month==12)))
clock_day=31;
break;
case 5:
clock_month=clock_month-1;
if(clock_month==0)
clock_month=12;
break;
default: break;
}
}
}
while(Down==0);
}
}
void keydone() //按键功能执行
{
if(flag1==0)
{
uchar Second;
if(flag==0) //关闭时钟,停止计时
{
DS1302_SetProtect(0); //写入允许
temp=Read1302(0x81); //将秒地址的数据读出来
Write1302(0x80,temp|0x80); //停止计时,秒寄存器最高位为1时停止计时
DS1302_SetProtect(1); //禁止写入
flag=1;
}
Setkey(); //扫描模式切换按键
switch(count)
{
case 1: //count=1,调整秒
do
{
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime1(DS1302_SECOND,miao); //将新的时间写入
DS1302_SetProtect(1); //禁止写入
up_flag=0;
down_flag=0;
}
hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶显示数据
}
while(count==2); //count=2,调整分
break;
case 2:
do
{
hide_sec=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime(DS1302_MINUTE,fen);
DS1302_SetProtect(1); //禁止写入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
}
while(count==3); //count=3,调整小时
break;
case 3:
do
{
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime(DS1302_HOUR,shi);
DS1302_SetProtect(1); //禁止写入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
}
while(count==4);
break;
case 4:
do //count=5,调整日
{
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime(DS1302_DAY,day);
DS1302_SetProtect(1); //写入禁止
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
}
while(count==6); //count=6,调整月
break;
case 5:
do
{
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime(DS1302_MONTH,month);
DS1302_SetProtect(1); //禁止写入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
}
while(count==7); //count=7,调整年
break;
case 6:
do
{
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
DS1302_SetProtect(0); //写入允许
DS1302_SetTime(DS1302_YEAR,year);
DS1302_SetProtect(1);
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
}
while(count==8); //count8, 跳出调整模式,
break;
case 7:
count=0;hide_year=0; //返回默认显示状态
DS1302_SetProtect(0); //写入允许
Second=Read1302(0x81); //读取秒地址的最新数据
Write1302(0x80,Second&0x7f); //开始计时
DS1302_SetProtect(1); //写入禁止
done=0;
flag1=0;flag2=0;
break;
default: break;
}
}
else
{
Setkey(); //扫描模式切换按键
switch(count1)
{
case 1: //count=1,调整秒
do
{
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
hi_sec++; //位闪计数
if(hi_sec>3)
hi_sec=0;
clock_dispaly(); //液晶显示数据
}
while(count1==2);
break;
case 2: //count=2,调整分
do
{
hi_sec=0;
outkey();
Upkey();
Downkey();
hi_min++;
if(hi_min>3)
hi_min=0;
clock_dispaly();
}
while(count==3);
break;
case 3: //count=3,调整小时
do
{
hi_min=0;
outkey();
Upkey();
Downkey();
hi_hour++;
if(hi_hour>3)
hi_hour=0;
clock_dispaly();
}
while(count==4);
break;
case 4: //count=4,调整日
do
{
hi_hour=0;
outkey();
Upkey();
Downkey();
hi_day++;
if(hi_day>3)
hi_day=0;
clock_dispaly();
}
while(count==5);
break;
case 5: //count=5,调整月
do
{
hi_day=0;
outkey();
Upkey();
Downkey();
hi_month++;
if(hi_month>3)
hi_month=0;
clock_dispaly();
}
while(count==6);
break;
case 6: //count=6,退出调整模式
count1=0;
hi_month=0;
flag1=0,flag2=0;
done=0;
LCD12864_WriteCmd(0x01); //清屏命令
LCD12864_WriteCmd(0x34); //扩展模式指令,关闭显示
LCD12864_ClearScreen(); //清除绘图
gui_line(72,32,72,48); //内部线框
gui_line(0,15,127,15);
gui_line(0,32,127,32);
gui_line(0,48,127,48);
gui_line(62,48,62,63);
gui_line(0,0,127,0); //四周线框
gui_line(0,1,0,63);
gui_line(0,63,127,63);
gui_line(127,0,127,63);
GUI_Put_Area(81,33,&uMod[0][0],16,14,0); //固定显示“星”
GUI_Put_Area(96,33,&uMod[1][0],16,14,0); //固定显示“期”
GUI_Put_Area(3,18,&uMod[2][0],16,12,0); //固定显示“农”
GUI_Put_Area(19,18,&uMod[3][0],16,12,0); //固定显示“历”
LCD12864_WriteCmd(0x36); //开显示
LCD12864_WriteCmd(0x30); //基本指令
break;
default: break;
}
}
}
void Setkey() //模式选择按键
{
if(Set==0) //时间调整模式
{
mdelay(8);
if(Set==0)
{
count=count+1; //Setkey按一次,count就加1
done=1; //进入调整模式
flag=0;
}
while(Set==0);
}
else if(clock_Set==0) //闹钟设置模式
{
mdelay(8);
if(clock_Set==0)
{
if(flag2==0)
{
flag2=~flag2;
LCD12864_WriteCmd(0x01); //清屏
}
flag1=1;
count1=count1+1;
done=1;
}
while(clock_Set==0);
}
else ;
}
void clock_than(SYSTEMTIME *time , CLOCKTIME *Time) //闹钟函数,响铃5秒
{
if((Time->Sec<=time->Second)&&(Time->Sec+5>=time->Second)&&(Time->Min==time->Minute)&&(Time->Hou==time->Hour)&&(Time->tian==time->Day)&&(Time->yue==time->Month))
{
Beep= 0; //响
}
else
{
Beep= 1; //不响
}
}
void init() //初始化函数
{
uchar Second;
Out=1;
Set=1;
Down=1;
Up=1;
Beep=1;
clock_Set=1;
up_flag=0;
down_flag=0;
done=0;
flag=0;
flag1=0,flag2=0;
count=0,count1=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
hi_sec=0,hi_min=0,hi_hour=0,hi_day=0,hi_month=0;
shi=0,fen=0,miao=0,week=0,day=0,year=0,month=0;
clock_shi=0,clock_fen=0,clock_miao=0,clock_month=10,clock_day=7;
IrValue[2]=0;
IT0=1; //下降沿触发
EX0=1; //打开中断0允许
EA=1; //打开总中断
IRIN=1; //初始化红外数据端口
LCD12864_Init(); //液晶初始化
DS18B20_init(); //温度传感器初始化函数
NRF24L01Int(); //无线模块初始化函数
gui_line(72,32,72,48); //内部线框
gui_line(0,15,127,15);
gui_line(0,32,127,32);
gui_line(0,48,127,48);
gui_line(62,48,62,63);
gui_line(0,0,127,0); //四周线框
gui_line(0,1,0,63);
gui_line(0,63,127,63);
gui_line(127,0,127,63);
GUI_Put_Area(81,33,&uMod[0][0],16,14,0); //固定显示“星”
GUI_Put_Area(96,33,&uMod[1][0],16,14,0); //固定显示“期”
GUI_Put_Area(3,18,&uMod[2][0],16,12,0); //固定显示“农”
GUI_Put_Area(19,18,&uMod[3][0],16,12,0); //固定显示“历”
LCD12864_WriteCmd(0x32); //绘图显示开
LCD12864_WriteCmd(0x30); //基本指令
DS1302_SetProtect(0); //写入允许
Second=Read1302(0x81);
Write1302(0x80,Second&0x7f); //开始计时
DS1302_SetProtect(1); //写入禁止
timer0_1(); //定时器初始化
//Initial_DS1302(); //时钟芯片初始化,第一次使用DS1302时可以初始化一下,以后就不用了
}
void main()
{
init();
while(1){
}
}
void T0_time() interrupt 1 //定时器0
{
uchar i;
TH0 = (65536 - 45872)/256;
TL0 = (65536 - 45872)%256;
i++;
if(i==5) //0.25秒
{
i=0;
if(done==1)
{
keydone(); //进入调整模式
}
if(done==0)
{
if(flag1==0)
show_time(); //时间显示
else
clock_(); //闹钟显示
clock_than(&CurrentTime ,&clock_time); //比较闹钟时间和实时时间
}
DS18B20_get(); //得到温度
NRF_rx(); //无线接收温度
Setkey(); //扫描设置按键
}
}
void ReadIr() interrupt 0 //外部中断0,红外数据接收
{
unsigned char j,k;
unsigned int err;
uchar Second;
Time=0;
DelayMs(70);
if(IRIN==0) //确认是否真的接收到正确的信号
{
err=1000; //1000*10us=10ms,超过说明接收到错误的信号
/*当两个条件都为真是循环,如果有一个条件为假的时候跳出循环,免得程序出错的时
侯,程序死在这里*/
while((IRIN==0)&&(err>0)) //等待前面9ms的低电平过去
{
DelayMs(1);
err--;
}
if(IRIN==1) //如果正确等到9ms低电平
{
err=500;
while((IRIN==1)&&(err>0)) //等待4.5ms的起始高电平过去
{
DelayMs(1);
err--;
}
for(k=0;k<4;k++) //共有4组数据
{
for(j=0;j<8;j++) //接收一组数据
{
err=60;
while((IRIN==0)&&(err>0))//等待信号前面的560us低电平过去
{
DelayMs(1);
err--;
}
err=500;
while((IRIN==1)&&(err>0)) //计算高电平的时间长度。
{
DelayMs(1);//0.14ms
Time++;
err--;
if(Time>30)
{
EX0=1;
return;
}
}
IrValue[k]>>=1; //k表示第几组数据
if(Time>=8) //如果高电平出现大于565us,那么是1
{
IrValue[k]|=0x80;
}
Time=0; //用完时间要重新赋值
}
}
}
if(IrValue[2]!=~IrValue[3])
{
return;
}
if((IrValue[2]==0x0c)) //按键1
{
done=1; //进入调整模式
flag=0;
count=count+1; //Setkey按一次,count就加1
}
if((IrValue[2]==0x18)) //按键2
{
if(flag2==0)
{
flag2=~flag2;
LCD12864_WriteCmd(0x01);
}
flag1=1;
count1=count1+1;
done=1;
}
if((IrValue[2]==0x15)) //按键VOL-
{
if(flag1==0)
{
switch(count)
{
case 1:
DS1302_change(0x81,&miao);
miao=miao-1;
if(miao==-1)
miao=59;
down_flag=1;
break;
case 2:
DS1302_change(0x83,&fen);
fen=fen-1;
if(fen==-1)
fen=59;
down_flag=1;
break;
case 3:
DS1302_change(0x85,&shi);
shi=shi-1;
if(shi==-1)
shi=23;
down_flag=1;
break;
case 4:
DS1302_change(0x87,&day);
DS1302_change(0x89,&month);
day=day-1;
if(day==0&&((month==4)||(month==6)||(month==9)||(month==11)))
day=30;
if(day==0&&(month==2))
day=29;
if(day==0&&((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12)))
day=31;
down_flag=1;
break;
case 5:
DS1302_change(0x89,&month);
month=month-1;
if(month==0)
month=12;
down_flag=1;
break;
case 6:
DS1302_change(0x8d,&year);
year=year-1;
if(year==-1)
year=99;
down_flag=1;
break;
default: break;
}
}
else
{
switch(count1)
{
case 1:
clock_miao=clock_miao-1;
if(clock_miao==-1)
clock_miao=59;
break;
case 2:
clock_fen=clock_fen-1;
if(clock_fen==-1)
clock_fen=59;
break;
case 3:
clock_shi=clock_shi-1;
if(clock_shi==-1)
clock_shi=23;
break;
case 4:
clock_day=clock_day-1;
if(clock_day==0&&((clock_month==4)||(clock_month==6)||(clock_month==9)||(clock_month==11)))
clock_day=30;
if(clock_day==0&&(clock_month==2))
clock_day=29;
if(clock_day==0&&((clock_month==1)||(clock_month==3)||(clock_month==5)||(clock_month==7)||(clock_month==8)||(clock_month==10)||(clock_month==12)))
clock_day=31;
break;
case 5:
clock_month=clock_month-1;
if(clock_month==0)
clock_month=12;
break;
default: break;
}
}
}
if((IrValue[2]==0x09)) //按键VOL+
{
if(flag1==0)
{
switch(count)
{
case 1:
DS1302_change(0x81,&miao);
miao=miao+1;
if(miao>=60)
miao=0;
down_flag=1;
break;
case 2:
DS1302_change(0x83,&fen);
fen=fen+1;
if(fen>=60)
fen=0;
down_flag=1;
break;
case 3:
DS1302_change(0x85,&shi);
shi=shi+1;
if(shi>=24)
shi=0;
down_flag=1;
break;
case 4:
DS1302_change(0x87,&day);
DS1302_change(0x89,&month);
……………………
…………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
电子万年历.7z
(167.33 KB, 下载次数: 23)
2019-2-19 13:36 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
wanglx
时间:
2019-2-27 11:17
感谢楼主,学习中
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1