有详尽的注释,有兴趣的同学可以焊接一个实物烧进去试试,因为不用RTC芯片也不用担心换纽扣电池,12MHZ的晶振带软件补偿日误差可以调节到1S以内。调节方法就是算出每误差1S的情况然后改buchang参数的值就可以了。因为手头只有一个多余的DHT11温湿度了所以用18B20的温度和DHT11湿度,实际上温度精度很高,湿度也凑合吧,如果那天有了更好的湿度传感器再改改湿度程序。
单片机源程序如下:
- #include <reg52.h>
- typedef unsigned int u16;
- typedef unsigned char u8;
- sbit k2=P3^2; //K1 K2 K3 K4按键接口,建议从左到右接K1-K4
- sbit k1=P3^5;
- sbit k3=P3^3;
- sbit k4=P3^4;
- sbit DQ=P3^6;
- sbit beep=P1^6;
- sbit Data=P2^0; //有源蜂鸣器在P16口
- sbit lcden=P1^4; //LCD1602接口定义
- sbit lcdrs=P1^0;
- sbit lcdrw=P2^6;
- sbit bg=P2^7; //背光变量接入LCD1602的K极,通过bg的高低电平就可控制自动熄灭与点亮
- u8 k,e,d,o=1,p=1,temp,nxflag=0,mbflag=0,tianmax;
- float temperature; //温度变量,18B20接收时为浮点数
- u8 miao1,miao2,fen1,fen2,shi1,shi2,tian1,tian2,wk,tem1,tem2,tem3,wendufu;
- u8 day=1,mon=1,day1,day2,yue1,yue2,mbw,n=0,m=0,beiguang,RH,RL,TH,TL,tempH,tempL;
- u8 se1,se2,mon1,mon2,hou1,hou2,min1,min2,MB2,nian1,nian2,nian3,nian4;
- u16 y,MB1;
- u16 temper,buchang,tempwarn=0,tempwarn1=500; //tempwarn为温度下限,1为温度上限
- u8 code set[]={"NaoZhong Status"}; //上电后傻瓜调节模块
- u8 code tempwarng[]={"Wendu Waring!"};
- u8 code temmin[]={"Min"};
- u8 code temmax[]={"Max"};
- u8 code naozhongON[]={" ON"};
- u8 code naozhongOFF[]={"OFF"};
- u8 code setsucces[]={"Set Success!"};
- u8 code thanks[]={"Welcome to use !"};
- u8 code thanksu[]={"thanks for using"};
- u8 code make[]={"Designed by LY"};
- u8 code MB[]={"Stopwatch"};
- u8 code week1[]={"[MON]"};
- u8 code week2[]={"[TUE]"};
- u8 code week3[]={"[WED]"};
- u8 code week4[]={"[THU]"};
- u8 code week5[]={"[FRI]"};
- u8 code week6[]={"[SAT]"};
- u8 code week7[]={"[SUN]"};
- void delay(unsigned int z) //定义延时函数
- {
- unsigned int x,y;
- for(x=z;x>0;x--)
- for(y=1;y>0;y--);
- }
- void DHT11_delay_us(u8 n)
- {
- while(--n);
- }
- void DHT11_delay_ms(u16 z) //定义DHT11延迟函数
- {
- u16 i,j;
- for(i=z;i>0;i--)
- for(j=110;j>0;j--);
- }
- void DHT11_start()
- {
- Data=1;
- DHT11_delay_us(2);
- Data=0;
- DHT11_delay_ms(20); //延时18ms以上
- Data=1;
- DHT11_delay_us(30);
- }
- u8 DHT11_rec_byte() //接收一个字节
- {
- u8 i,dat=0;
- for(i=0;i<8;i++) //从高到低依次接收8位数据
- {
- while(!Data); //等待50us低电平过去
- DHT11_delay_us(8); //延时60us,如果还为高则数据为1,否则为0
- dat<<=1; //移位使正确接收8位数据,数据为0时直接移位
- if(Data==1) //数据为1时,使dat加1来接收数据1
- dat+=1;
- while(Data); //等待数据线拉低
- }
- return dat;
- }
- void DHT11_receive() //接收40位的数据
- {
- u8 R_H,R_L,T_H,T_L,revise;
- DHT11_start();
- if(Data==0)
- {
- while(Data==0); //等待拉高
- DHT11_delay_us(40); //拉高后延时80us
- R_H=DHT11_rec_byte(); //接收湿度高八位
- R_L=DHT11_rec_byte(); //接收湿度低八位
- T_H=DHT11_rec_byte(); //接收温度高八位
- T_L=DHT11_rec_byte(); //接收温度低八位
- revise=DHT11_rec_byte(); //接收校正位
- DHT11_delay_us(25); //结束
- if((R_H+R_L+T_H+T_L)==revise) //校正
- {
- RH=R_H;
- RL=R_L;
- TH=T_H;
- TL=T_L;
- }
- }
- }
- void beepon() //PWM(如果你是无源蜂鸣器,这里写PWM函数)
- { //当前为有源蜂鸣器,有源蜂鸣器无需更改
- beep=0;
- delay(1200);
- beep=1;
- }
- void write_nian(); //预定义
- void write_yue();
- void write_tian();
- void write_shi();
- void write_fen();
- void write_miao();
- void write_week();
- void zhuanhuan();
- void write_temp();
- void write_nz();
- void nzON();
- void write_setsuccess();
- void beiguangpd();
- void write_com(u8 com) //LCD1602初始化程序,了解1602时序图后新手的话可以直接照搬使用
- {
- lcdrs=0;
- P0=com;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void write_data(u8 date)
- {
- lcdrs=1;
- P0=date;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void init()
- {
- lcdrw=0;
- lcden=0;
- write_com(0x38);
- write_com(0x0c);
- write_com(0x06);
- write_com(0x01);
- write_com(0x80+0x10);
- }
- void Timer0Init() //定时器0工作方式1 中断初始化,923位12M晶振在KEIL仿真后的计算结果
- {
- TMOD=0X01;
- TH0=(65535-901)/256;
- TL0=(65535-901)%256;
- ET0=1; //打开定时器0中断允许位
- EA=1; //打开总中断允许
- TR0=1; //打开 定时器0,开始计时
- }
- Init_DS18B20(void) //DS18B20初始化与时序图程序,仿真时温度问题改进这个初始化程序就解决了
- {
- DQ=1;
- delay(70);
- DQ=0;
- delay(485);
- DQ=1;
- delay(50);
- }
- ReadOneChar(void) //18B20读一个字节
- {
- unsigned char i=0;
- unsigned char dat=0;
- for (i=8;i>0;i--)
- {
- DQ=1;
- delay(1);
- DQ=0;
- dat>>=1;
- DQ=1;
- if(DQ)
- dat|=0x80;
- delay(4);
- }
- return(dat);
- }
- WriteOneChar(unsigned char dat) //18B20写一个字节
- {
- unsigned char i=0;
- for(i=8;i>0;i--)
- {
- DQ=0;
- DQ=dat&0x01;
- delay(5);
- DQ=1;
- dat>>=1;
- }
- delay(4);
- }
- ReadTemperature(void) //读取温度函数定义,返回值为浮点数
- {
- Init_DS18B20();
- WriteOneChar(0xcc);
- WriteOneChar(0x44);
- delay(125);
- Init_DS18B20();
- WriteOneChar(0xcc);
- WriteOneChar(0xbe);
- tempL=ReadOneChar();
- tempH=ReadOneChar();
- if(tempH>0x7f)
- {
- tempH=~tempH;
- tempL=~tempL+1;
- wendufu=1;
- }
- else
- wendufu=0;
- temperature=(((tempH*256)+tempL)*0.0625)*10;
- delay(200);
- return(temperature);
- }
- void welcome() //定义欢迎函数
- { static u8 i;
- init(); //初始化1602
- delay(5000);
- for(i=0;i<16;i++)
- {
- write_com(0x80+i);
- write_data(thanks[i]);
- delay(4000);
- }
- delay(50000);
- for(i=0;i<14;i++)
- {
- write_com(0x81+0x40+i);
- write_data(make[i]);
- delay(4000);
- }
- delay(50000);
- delay(50000);
- }
- void pdtian1() //PD在上电后设置完毕主界面处的天数判断
- {
- if((p==1||p==3)||(p==5||p==7)||(p==8||p==10)||p==12)
- tianmax=31;
- if((p==4||p==6)||(p==9||p==11))
- tianmax=30;
- if(p==2)
- {
- if(((y%4==0)&&(y%100!=0))||(y%400==0))
- tianmax=29;
- else
- tianmax=28;
- }
- }
- void pdxingqi1() //PD在上电后设置完毕至主界面处的星期判断
- {
- static char c,yi,mt,xwk1,xwk2,xwk3;
- static int xwk,yn,xwk4;
- yn=y;
- if(p==1||p==2)
- { yn=yn-1;
- mt=p+12;
- }
- else
- mt=p;
- yi=yn%100;
- c=yn/100;
- xwk1=yi+(yi/4);
- xwk2=c/4;
- xwk3=2*c;
- xwk4=(26*mt+26)/10;
- xwk=xwk1+xwk2-xwk3+xwk4+o-1;
- while(xwk<0)
- {xwk+=7; }
- wk=xwk%7;
- }
- void Display() //定义主程序 显示部分函数模块
- { static u16 xunhuan;
- RH=RH%100;
- write_nian(); //1602写入显示年
- write_com(0x84);
- write_data('-');
- write_yue(); //写入月
- write_com(0x87);
- write_data('-');
- write_com(0x88);
- write_tian(); //写入天
- write_week();
- write_shi();
- write_com(0x82+0x40);
- write_data(':');
- write_fen();
- write_com(0x85+0x40);
- write_data(':');
- write_miao(); //写入温度,温度TEM1与2与3是温度的三位数
- xunhuan++;
- if(xunhuan<180)
- {if(wendufu==1)
- {
- if((temper/100)!=0)
- {
- write_com(0x89+0x40);
- write_data('-');
- write_com(0x8a+0x40);
- write_data(tem1);
- }
- else
- {
- write_com(0x89+0x40);
- write_data(' ');
- write_com(0x8a+0x40);
- write_data('-');
- }
- }
- else
- {
- write_com(0x89+0x40);
- write_data(' ');
-
- if((temper/100)!=0)
- {
- write_com(0x8a+0x40);
- write_data(tem1);
- }
- else
- {
- write_com(0x8a+0x40);
- write_data(' ');
- } }
- write_com(0x8b+0x40);
- write_data(tem2);
- write_com(0x8c+0x40);
- write_data('.');
- write_com(0x8d+0x40);
- write_data(tem3);
- write_com(0x8e+0x40);
- write_data(0xdf);
- write_com(0x8f+0x40);
- write_data('C');
- }
- if(xunhuan>180)
- {
- write_com(0x89+0x40);
- write_data(' ');
- write_com(0x8a+0x40);
- write_data(' ');
- write_com(0x8b+0x40);
- write_data(RH/10+0x30);
- write_com(0x8c+0x40);
- write_data(RH%10+0x30);
- write_com(0x8d+0x40);
- write_data('%');
- write_com(0x8e+0x40);
- write_data('R');
- write_com(0x8f+0x40);
- write_data('H');
- }
- if(xunhuan==360)
- xunhuan=0;
- }
- void NZdisplay() //定义闹钟模块
- {
- static u8 nzflag=2,nzwei;
- delay(2000);
- init();
- delay(2000);
- nzON(); //闹钟开关选择模块
- while(k4) //没有检测到K4键退出时无限循环
- {
- write_nz(); //写入闹钟模块
- if(k3==0) //判断K3键是否按下
- {
- delay(5000);
- if(k3==0) //延时消抖
- {beepon(); //响一声
- if(nxflag==0) //如果NXFLAG为0,闹钟为关闭状态,给其赋值为1,
- nxflag=1;
- else
- nxflag=0;
- }
- nzON(); //判断闹钟的状态
- }
- if(k1==0) //如果K1键按下后
- {
- delay(8000);
- if(k1==0)
- {
- beepon();
- if(nzwei==0) //通过NZWEI来判断当前光标的位置与设置小时还是分钟
- nzflag=0;
- if(nzwei==1)
- nzflag=1;
- }
- }
- if(nzflag==0)
- {
- while(1)
- {
- write_com(0x83+0x40); //光标闪烁
- write_data(0xff);
- delay(5000);
- write_nz(); //写入闹钟
- delay(5000);
- if(k2==0) //如果K2为0
- {
- delay(50);
- if(k2==0)
- {
- beepon(); //判断小时状态,进行+1
- if(n<23)
- n+=1;
- else
- n=0;
- }
- }
- if(k3==0) //如果K3为0
- {
- delay(50);
- if(k3==0) //判断小时状态,进行-1 最大溢出重回最小,最小溢出重回最大
- {
- beepon();
- if(n>0)
- n-=1;
- else
- n=23;
- }
- }
- if(k1==0)
- {
- delay(1000); //如果K1按下,更改NZFLAG,更改闹钟光标位
- if(k1==0)
- {
- nzflag=1;
- beepon();
- break;
- }
- }
- if(k4==0) //如果K4按下,退出。给NZFLAG重新赋值为2,取消光标并下次进入不会直接进入光标
- {
- beepon();
- delay(6000);
- nzflag=2;
- nzwei=0;
- break; }
- }
- }
- if(nzflag==1) //如果NZ为1,同上,此时为分钟调节
- { while(1)
- {
- write_com(0x86+0x40);
- write_data(0xff);
- delay(5000);
- write_nz();
- delay(5000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(m<59)
- m+=1;
- else
- m=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if(m>0)
- m-=1;
- else
- m=59;
- }
- }
- if(k1==0)
- {
- delay(1000);
- if(k1==0)
- {
- beepon();
- nzflag=0;
- break;
- }
- }
- if(k4==0)
- {
- beepon();
-
- delay(6000);
- nzflag=2;
- nzwei=1;
- break; }
- }
- }
- if(k4==0)
- {
- beepon();
- delay(30000);
- break;
- }
- }
- nzflag=2;
- init();
- }
- void temperwaring() //定义温度警报模块
- {
- static u8 temflag=2,temwei;
- delay(5000);
- init();
- delay(5000);
- while(k4)
- {
- write_temp(); //写入温度
- if(k3==0) //如果K3为0,为其赋值为N0-N0,关闭温度警报,并且不会闪烁光标
- {
- beepon();
- delay(3000);
- tempwarn=(0X4e-0x30)*100;
- tempwarn1=(0X4e-0x30)*100;
- }
- if(k1==0) //如果K1为0,进入光标位,光标闪烁,根据temwei不同进入不同的初始闪烁位置
- {
- delay(8000);
- if(k1==0)
- {
- beepon();
- if(temwei==0) //为只需单独打开温度上限或下限报警时提供方便
- temflag=0;
- if(temwei==1)
- temflag=1;
- }
- }
- if(temflag==0) //和闹钟模块 类似,如果temflag为0的话进入下限调整,否则进入上限调整
- {
- while(1)
- {
- write_com(0x86+0x40);
- write_data(0xff);
- delay(6000);
- write_temp();
- delay(4000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(tempwarn<500) //温度范围为精确到小数点后1位,500为50.0度,自己设置每次只调节1度
- tempwarn+=10; //如果需要温度报警精确到0.1度,请将此处改为1并重新修改界面
- else
- tempwarn=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if(tempwarn>0&&(tempwarn!=(0X4e-0x30)*100)) //K3键按下,判断当在关闭状态与一般状态时,温度阀门下限减1度
- tempwarn-=10;
- else
- tempwarn=500;
- }
- }
- if(k1==0) //如果检测K1按下,跳出循环,给FLAG重新赋值为1,光标开始在温度上限处闪烁
- { delay(1000); //并且开始调节温度上限
- temflag=1;
- beepon();
- break;
- }
- if(k4==0) //如果K4等于0,第一次确定,光标停止闪烁,K2K3不会更改数值
- { //目的是在确定无误后在下次按下K4时可以直接退出
- beepon();
- delay(6000);
- temflag=2;
- temwei=0;
- break; }
- }
- }
- if(temflag==1) //进入温度修改上限部分,同温度修改下限
- { while(1)
- {
- write_com(0x89+0x40);
- write_data(0xff);
- delay(6000);
- write_temp();
- delay(4000);
- if(k2==0)
- {
- delay(50);
- if(k2==0)
- {
- beepon();
- if(tempwarn1<500)
- tempwarn1+=10;
- else
- tempwarn1=0;
- }
- }
- if(k3==0)
- {
- delay(50);
- if(k3==0)
- {
- beepon();
- if((tempwarn1>0)&&(tempwarn1!=(0X4e-0x30)*100))
- tempwarn1-=10;
- else
- tempwarn1=500;
- }
- }
- if(k1==0)
- {beepon();
- delay(1000);
- temflag=0;
- break;
- }
- if(k4==0)
- {
- beepon();
-
- delay(6000);
- temflag=2;
- temwei=1;
- break; }
- }
- }
- if(k4==0) //当光标不闪烁时,按下K4键,直接退出
- {
- beepon();
- delay(30000);
- break;
- }
- }
- temflag=2; //temflag重新赋值为2,目的是确保下次进入不会直接进入光标调节模块
- init();ET0=1; //这样就可以方便的快速关闭温度报警及快速设置上下限
-
- }
- void miaobiaods() //定义秒表显示模块
- {
- static u8 i,times;
- delay(1000);
- init();
- delay(10000);
- while(1)
- {
- if(MB1==10000) //MB1位16位数,所以秒表在0.00-100.00的计数范围使用MB1,超出后清0累加MB2
- {
- MB1=0;MB2++;
- }
- if(MB2==100) //如果秒表超出了10000秒,直接清零,若想修改更大秒表范围请将MB2定义为16位数再修改,并修改显示界面
- {MB2=0;MB1=0;
- mbflag=0;
- }
- for(i=0;i<9;i++) //1602循环显示STOPWATCH
- {
- write_com(0x84+i);
- write_data(MB[i]);
- }
- write_com(0x83+0x40); //显示秒表运行状态模块
- write_data(times/10+0x30);
- write_com(0x84+0x40);
- write_data(times%10+0x30); //TIMES为计数部分,不为0时每次暂停可以计数一次
- write_com(0x86+0x40);
- write_data(MB2/10+0x30);
- write_com(0x87+0x40); //秒表高位MB2与低位MB1转换为16进制数显示
- write_data(MB2%10+0x30);
- write_com(0x88+0x40);
- write_data('.');
- write_data((MB1/1000)+0x30);
- write_com(0x8a+0x40);
- write_data(MB1%1000/100+0x30);
- write_com(0x8b+0x40);
- write_data('.');
- write_com(0x8c+0x40);
- write_data(MB1%1000%100/10+0x30);
- write_com(0x8d+0x40);
- write_data(MB1%1000%100%10+0x30);
- if(k1==0) //由于秒表对精度要求很高,必须直接中断不能延时
- {mbflag=1; //因此也不能只用一个K1进行开始于暂停
- beepon(); } //此时按下K1键为打开秒表,会有立刻的响铃以便直观表明计时开始
- if(k2==0) //和以上原因一样,秒表暂停
- {mbflag=0; //按下K2键为暂停
- beepon();
- if(MB1!=0) //如果不为0,计次+1
- { delay(40000);
- if(times<99) //计次范围0-99
- times+=1;
- }
- }
- if(k3==0) //按下K3,秒表数据清0
- {beepon();
- mbflag=0;
- times=0;
- MB1=0;
- MB2=0;
- }
- if(k4==0)
- {beepon(); //K4为0,退出秒表,如果打开秒表也可直接退出,秒表与时间并不冲突
- break;}
- }
- delay(1000);
- init(); //延时初始化,确保时间充足无乱码
- delay(10000);
- }
- void naozhongfamen() //主界面上判断是否进入闹钟设置界面的模块
- {
- if(k3==0)
- {
- delay(50000); //如果K3长按,进入闹钟
- if(k3==0)
- {
- beepon();
- delay(3000);
- NZdisplay();
- delay(10000);
- write_setsuccess();
- delay(30000);
- init();
- }
- }
- }
- void wendufamen() //主界面上判断是否进入温度报警设置界面的模块
- {
- if(k2==0)
- {
- delay(50000);
- if(k2==0)
- { beepon();
- delay(3000);
- temperwaring();
- delay(10000);
- write_setsuccess();
- delay(30000);
- init();
- }
- }
- }
- void miaobiao() //主界面上判断是否进入秒表的模块
- { if(mbflag==1)
- {
- if(MB1>10000)
- {
- MB1=0;MB2++;
- }
- if(MB2==100)
- {MB2=0;MB1=0;
- mbflag=0;
- }
- }
- if(k4==0)
- {
- delay(50000);
- if(k4==0)
- {
- beepon();
- delay(3000);
- miaobiaods();
- delay(10000);
- init();
- }
- }
- }
- void Timer0() interrupt 1 //定义中断函数,923为12M晶振的精度,如果是11.05M晶振请根据仿真或实测自行改变这个值
- {
- static u16 i;
- TH0=(65535-901)/256;
- TL0=(65535-901)%256;
- i++; //i为秒,不断累加
- beiguangpd(); //进行背光判断,确保背光第一时间响应
- if(mbflag==1)
- { //如果检测到打开秒表了,就开始秒表位累加
- mbw++;
- if(mbw==10)
- {
- mbw=0;
- MB1++;
- }
- }
- if(i==1000) //如果检测到1000,秒+1
- {
- k++; i=0;
- if(beiguang<60) //如果背光变量小于60,此时背光打开
- beiguang++;
- buchang++;
- DHT11_receive();
- temper=ReadTemperature(); //检测温度,检测周期是1S
- }
- if(k==60) //判断各个变量,也可将这些放到其他模块里,但是精度未必会提高
- {
- k=0;
- e++;
- }
- if(buchang==4955) //精度补偿部分,不一定适合你的晶振
- {
- buchang=0;k+=1;
- }
- if(e==60)
- {
- e=0;
- d++;
- }
- if(d==24)
- {
- d=0;
- o++;
- if(wk<6)
- wk++;
- else
- wk=0;
- }
- if(o==tianmax+1)
- {
- o=1;
- p++;
- }
- if(p==13)
- {
- p=1;
- y++;
- }
- }
- void bijiao() //比较模块,也是报警触发模块
- {
- static u8 gbflag;
- if(m==e&&n==d) //如果闹钟时间相同,开始响铃,时长1分钟
- {
- if(gbflag==0) //如果不是在响铃并按键关闭后,才会响铃
- {
- if(nxflag==1) //如果闹钟为开启状态响铃,否则不响
- beepon();
- if(k2==0||k3==0||k4==0) //如果有K2,K3,K4任何一个按键触发,就会将gbflag设置为1,停止响铃
- gbflag=1; //因为K1键快速按下还有快捷粗调暂停1秒的功能,所以没有K1键
- }
- }
- else
- gbflag=0; //响铃完毕后给gbflag赋值为0;
- if(e==0&&k==0) //整点报时模块,设置为7到24点整点报时,可改范围,不会影响休息也比较合适
- {if((d>6&&d<24)||d==0)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100))
- {
- if(wendufu==1)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100)||(tempwarn1!=(0X4e-0x30)*100)) //判断温度阀门打开了上限还是下线还是关闭还是上下限同时打开
- {
- if((tempwarn==(0x4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100)) //判断完毕后只要触发就会报警
- {
- if(tempwarn1<temper)
- {
- beepon();
-
- }
- }
- if((tempwarn!=(0x4e-0x30)*100)&&(tempwarn1==(0X4e-0x30)*100))
- {
- if(tempwarn>temper)
- beepon();
- }
- if((tempwarn!=(0X4e-0x30)*100)&&(tempwarn1!=(0X4e-0x30)*100))
- {
- if((tempwarn>temper)||(tempwarn1<temper))
- {
- beepon();
-
- }
- }
- }
- }
- void zhuanhuan() //转换模块,将时间变量转换为1602的16位显示数值
- {
-
- nian1=(y/1000)+0x30;
- nian2=(y%1000/100)+0x30;
- nian3=(y%1000%100/10)+0x30;
- nian4=(y%1000%100%10)+0x30;
- yue1=(p/10)+0x30;
- yue2=(p%10)+0x30;
- tian1=(o/10)+0x30;
- tian2=(o%10)+0x30;
- shi1=(d/10)+0x30;
- shi2 =(d%10)+0x30;
- fen1=(e/10)+0x30;
- fen2=(e%10)+0x30;
- miao1=(k/10)+0x30;
- miao2=(k%10)+0x30;
- tem1=(temper/100)+0x30;
- tem2=(temper%100/10)+0x30;
- tem3=(temper%100%10)+0x30;
- }
- void tiaojie() //光标调节时间模块
- {
- static u8 flag=0;
- if(k1==0) //检测到K1按下一段时间后,开始调节光标
- {
- delay(30000);
- if(k1==0)
- {
- beepon(); //因为会关闭中断并且停秒,所以给软件补偿buchang值清0
- buchang=0;
- while(1)
- {
- ET0=0;
- pdtian1(); //此时中断已关闭,开始循环判断
- pdxingqi1(); //判断天数与星期,比如在将时间调到3月31号后再调到2月
- zhuanhuan();
- if(o>tianmax)
- o=tianmax;
- write_week(); //天数就会自动调节到28日,确保不会超出范围,并自动调出星期
- write_tian();
- if(k4==0) //如果按下K4,就停止时间光标调节并跳出循环
- {
- beepon(); break;
- }
- if(flag==0) //flag调节位置判断位
- {
- write_miao();
- delay(5000);
- write_com(0x87+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- { //此时调秒
- beepon();
- if(k<59) k+=1;
- else k=0;
- }
- if(k3==0)
- {
- beepon();
- if(k>0) k-=1;
- else k=59;
- }
- if(k1==0)
- {
- beepon();
- flag+=1; }
- write_miao();
- }
- if(flag==1) //此时调分
- {
- write_fen();
- delay(5000);
- write_com(0x84+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(e<59) e+=1;
- else e=0; }
- if(k3==0)
- {
- beepon();
- if(e>0) e-=1;
- else e=59;
- }
- if(k1==0)
- {
- beepon();
- flag+=1; }
- write_fen();
- }
- if(flag==2) //此时调时
- {
- write_shi();
- delay(5000);
- write_com(0x81+0x40);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(d<23) d+=1;
- else d=0;
- }
- if(k3==0)
- {
- beepon();
- if(d>0) d-=1;
- else d=23;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;}
- write_shi();
- }
- if(flag==3) //此时调天 天、月、年会影响星期,所以在这里加入判断星期模块
- {
- write_tian();
- delay(5000);
- write_com(0x89);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(o<tianmax)
- o+=1;
- else
- o=1;
- }
- if(k3==0)
- {
- beepon();
- pdtian1();
- if(o>1)
- o-=1;
- else
- o=tianmax;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;
- }
- write_tian();
- }
- if(flag==4)
- {
- write_yue(); //此时调月
- delay(5000);
- write_com(0x86);
- write_data(0xff); //循环闪烁光标
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(p<12)
- p+=1;
- else
- p=1;
- }
- if(k3==0)
- {
- beepon();
- if(p>1)
- p-=1;
- else
- p=12;
- if(o>tianmax)
- o=tianmax;
- }
- if(k1==0)
- {
- beepon();
- flag+=1;
- }
- write_yue();
- }
- if(flag==5)
- {
- write_nian(); //此时调年
- delay(5000);
- write_com(0x83);
- write_data(0xff);
- delay(5000);
- if(k2==0)
- {
- beepon();
- if(y<9999)
- y+=1;
- else
- y=1;
-
- }
- if(k3==0)
- {
- beepon();
- if(y>0)
- y-=1;
- else
- y=9999;
-
- }
- if(k1==0)
- {
- beepon();
- flag=0;}
- write_nian();
- }
- //调节完毕并且K4确认后打开中断允许,开始走时
- }
- }
- }
- ET0=1;
-
- }
- void beiguangpd() //背光判断模块
- {if(k1==0||k2==0||k3==0|k4==0)
- { if(bg==1) //如果再背光熄灭的情况下 ,按下任何键都会打开背光并响铃
- beepon();
- beiguang=0; //无论是否熄灭,按下都会清零
- }
- if(beiguang==60) //如果检测到没有按键60S,背光自动熄灭
- bg=1;
- else
- bg=0;
- }
- void main() //主函数
- { bg=0;
- y=2017;p=5;o=25;
- DHT11_receive();
- temper=ReadTemperature();
- welcome(); //欢迎
- NZdisplay(); //断电后第一个调节闹钟
- init();
- Timer0Init(); //初始化定时器,但是没有打开ET0
- ET0=1;
- init(); //调节完毕后延时初始化并延时足够时间,确保不会乱码
- delay(50000);
- while(1) //循环各个模块且不会冲突
- {
- zhuanhuan();
- bijiao();
- tiaojie();
- naozhongfamen();
- wendufamen();
- miaobiao();
- pdtian1();
- pdxingqi1();
- Display();
- }
- }
- void write_week() //1602写并显示星期模块
- { static u8 i;
- switch (wk)
- {
- case(1):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week1[i]);
- }
- break;
- case(2):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week2[i]);
- }
- break;
- case(3):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week3[i]);
- }
- break;
- case(4):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week4[i]);
- }
- break;
- case(5):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week5[i]);
- }
- break;
- case(6):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week6[i]);
- }
- break;
- case(0):
- for(i=0;i<5;i++)
- {
- write_com(0x8b+i);
- write_data(week7[i]);
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
非RTC多功能万年历.zip
(96.67 KB, 下载次数: 184)
|